React学习日志4

五、事件处理

1、react事件处理与DOM相似但语法有不同

  • React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
  • 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。

// 传统html

<button οnclick="activateLasers()">

  Activate Lasers

</button>

// react

<button onClick={activateLasers}>

  Activate Lasers

</button>

  • 在 React 中不能通过返回 false 的方式阻止默认行为。你必须显式的使用 preventDefault 

// 传统html

<a href="#" οnclick="console.log('The link was clicked.'); return false">

  Click me

</a>

// react

function ActionLink() {

  function handleClick(e) {

    e.preventDefault();

    console.log('The link was clicked.');

  }

  return (

    <a href="#" onClick={handleClick}>

      Click me

    </a>

  );

}

  • 一般不需要使用 addEventListener 为已创建的 DOM 元素添加监听器。只需要在该元素初始渲染的时候添加监听器即可。

2、事件处理函数声明的方法

构造器绑定bind

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isToggleOn: true
    }
    // 为了在回调中使用 `this`,这个绑定是必不可少的
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick() {
    this.setState(state => ({
      isToggleOn: !state.isToggleOn
    }))
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    )
  }
}
ReactDOM.render(<Toggle />, document.getElementById('root'

使用 class fields 语法

class LoggingButton extends React.Component {


  // 此语法确保 `handleClick` 内的 `this` 已被绑定。
  // 注意: 这是 *实验性* 语法。
  handleClick = () => {
    console.log('this is:', this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }

回调中使用箭头函数

class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }
  render() {
    // 此语法确保 `handleClick` 内的 `this` 已被绑定。
    return (
      <button onClick={() => this.handleClick()}>
        Click me
      </button>
    );
  }

在回调中使用箭头函数在大多数情况下没什么问题,但如果该回调函数作为 prop 传入子组件时,这些组件可能会进行额外的重新渲染。我们通常建议在构造器中绑定或使用 class fields 语法来避免这类性能问题。

3、向事件处理程序传递参数

// 箭头函数 事件对象显式传递
<button onClick={(e) => this.deleteRow(id, e)}>
  Delete Row
</button>

// Function.prototype.bind 事件对象及更多参数隐式传递
<button onClick={this.deleteRow.bind(this, id)}>
  Delete Row
</button>

六、条件渲染

在 React 中,你可以创建不同的组件来封装各种你需要的行为。然后,依据应用的不同状态,你可以只渲染对应状态下的部分内容。

1、使用if或条件运算符

function UserGreeting(props) {
  return <h1>welcome back!</h1>
}

function GuestGreeting(props) {
  return <h1>please sign up.</h1>
}

function Greeting(props) {
  let isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <UserGreeting />
  }
  return <GuestGreeting />
}

ReactDOM.render(<Greeting isLoggedIn={false} />, document.getElementById('ro

2、元素变量

使用变量来储存元素。 它可以帮助你有条件地渲染组件的一部分,而其他的渲染部分并不会因此而改变。

function LoginButton(props) {
  return (<button onClick={props.onClick}>Login</button>)
}

function LogoutButton(props) {
  return (<button onClick={props.onClick}>Logout</button>)
}

class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isLoggedIn: false
    }
  }

  handleLoginClick() {
    this.setState({
      isLoggedIn: false
    })
  }

  handleLogoutClick() {
    this.setState({
      isLoggedIn: true
    })
  }

  render() {
    let isLoggedIn = this.state.isLoggedIn;
    let button;
    if (isLoggedIn) {
      button = <LoginButton onClick={() => this.handleLoginClick()} />
    } else {
      button = <LogoutButton 
                onClick=  {() => this.handleLogoutClick()} />
    }
    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />
        {button}
      </div>
    )
  }
}
ReactDOM.render(<LoginControl />, document.getElementById('ro

3、与运算符&&

true && expression 总是会返回 expression, 而 false && expression 总是会返回 false。

因此,如果条件是 true,&& 右侧的元素就会被渲染,如果是 false,React 会忽略并跳过它。

render() {
    let isLoggedIn = this.state.isLoggedIn;
    let button;
    if (isLoggedIn) {
      button = <LoginButton onClick={() => this.handleLoginClick()} />
    } else {
      button = <LogoutButton onClick={() => this.handleLogoutClick()} />
    }
    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />
        {isLoggedIn && button}
      </div>
    )
  }

4、三目运算符

另一种内联条件渲染的方法是使用 JavaScript 中的三目运算符 condition ? true : false。

render() {
    let isLoggedIn = this.state.isLoggedIn;
    let button = isLoggedIn ?
      <LoginButton onClick={() => this.handleLoginClick()} />
      :
      <LogoutButton onClick={() => this.handleLogoutClick()} />

    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />
        {button}
      </div>
    )
  

5、阻止组件渲染

可以让 render 方法直接返回 null,而不进行任何渲染 。返回 null 并不会影响组件的生命周期

function WarningBanner(props) {
  if (!props.warn) {
    return null
  }
  return (<div>Warning!</div>)
}

class Page extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      showWarning: true
    }
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick() {
    this.setState(state => ({
      showWarning: !state.showWarning
    }
    ));
  }

  render() {
    return (
      <div>
        <WarningBanner warn={this.state.showWarning} />
        <button onClick={this.handleClick} >
          {this.state.showWarning ? 'hide' : 'show'}
        </button>
      </div>
    )
  }
}
ReactDOM.render(<Page />, document.getElementById('roo

七、列表与key

1、渲染多个组件

通过使用 {} 在 JSX 内构建一个元素集合

let numbers = [1, 2, 3, 4, 5]
const listItems = numbers.map((item) =>
  <li>{item}</li>
)
ReactDOM.render(<ul>{listItems}</ul>, document.getElementById('root'))

2、基础列表组件

将前面的例子重构成一个组件

function NumberList(props) {
  let numbers = props.numbers;
  let listItems = numbers.map(item => <li>{item}</li>)
  return (
    <ul>{listItems}</ul>
  )
}
let numbers = [1, 2, 3, 4, 5]
ReactDOM.render(<NumberList numbers={numbers} />, document.getElementById('root'))

此时会报错:Warning: Each child in a list should have a unique "key"  prop.意思是要创建玩才能用。所以给每列元素分配一个key <li key={item.toString()}>{item}</li>

3、key

key 帮助 React 识别哪些元素改变了,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识。通常会使用数据中的 id 来作为元素的 key,万不得已你可以使用元素索引 index 作为 key

  • key提取组件:元素的key只有放在就近数组的上下文才有意义。
  • 一个好的经验法则是:在 map() 方法中的元素需要设置 key 属性
  • key 只是在兄弟节点之间必须唯一:当我们生成两个不同的数组时,我们可以使用相同的 key 值
  • key会传递信息给React但不会传递给组件,要使用key值要用其他属性显式传递

4、在JSX中嵌入map()

JSX 允许在大括号中嵌入任何表达式

function ListItem(props) {
  return (
    <li>{props.value}</li>
  )
}
// function NumberList(props) {
//   let numbers = props.numbers;
//   let listItems = numbers.map(number =>
//     <ListItem key={number.toString()} value={number} />)
//   return (
//     <ul>{listItems}</ul>
//   )
// }
// =============
function NumberList(props) {
  let numbers = props.numbers
  return (
    <ul>
      {
        numbers.map(number => <ListItem key={number.toString()} value={number} />)
      }
    </ul>
  )
}
let numbers = [11, 22, 33, 44, 55]
ReactDOM.render(<NumberList numbers={numbers} />, document.getElementById('root'))

八、表单

1、受控组件

在 HTML 中,表单元素(如<input>、 <textarea> 和 <select>)之类的表单元素通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。 把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。React 以这种方式控制取值的表单输入元素就叫做“受控组件”

class NameForm extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      name: ""
    }
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this)
  }

  handleChange(event) {
    this.setState({
      name: event.target.value
    })
  }

  handleSubmit(event) {
    console.log('提交的名字' + this.state.name)
    event.preventDefault()
  }
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          名字:<input type="text" value={this.state.name} onChange={this.handleChange} />
        </label>
        <input type="submit" value="提交" />
      </form>
    )
  }
}
ReactDOM.render(<NameForm />, document.getElementById('root

对于受控组件来说,输入的值始终由 React 的 state 驱动。

2、textarea标签

class TextArea extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      text: ""
    }
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this)
  }

  handleChange(event) {
    this.setState({
      text: event.target.value
    })
  }

  handleSubmit(event) {
    console.log('提交的名字' + this.state.text)
    event.preventDefault()
  }
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          文章:<textarea type="text" value={this.state.text} onChange={this.handleChange} />
        </label>
        <input type="submit" value="提交" />
      </form>
    )
  }
}
ReactDOM.render(<TextArea />, document.getElementById('root'

3、select标签

选中的实现--定义根select标签的value属性,而不使用selected

class SelectFrom extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      value: 3,
      selectArr: []
    }
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this)
  }

  handleChange(event) {
    console.log('修改', event.target.value)
    this.setState({
      value: event.target.value
    })
  }

  handleSubmit(event) {
    console.log('提交的选择' + this.state.value)
    event.preventDefault()
  }

  // 生命周期--挂载
  componentDidMount() {
    let selectArr = [
      {
        "code": 1,
        "name": "a",
      },
      {
        "code": 2,
        "name": "b",
      },
      {
        "code": 3,
        "name": "c",
      },
      {
        "code": 4,
        "name": "d",
      },
      {
        "code": 5,
        "name": "e",
      },
    ]
    this.setState({
      selectArr: selectArr,
    })
  }
  render() {
    let arr = this.state.selectArr
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          选择:
          <select value={this.state.value} onChange={this.handleChange}>
            {
              arr.map((item, index) =>
                < OptionItem key={index} value={item.code} name={item.name} />
              )
            }
          </select>
        </label>
        <input type="submit" value="提交" />
      </form>
    )
  }
}
function OptionItem(props) {
  return (
    <option value={props.value}>{props.name}</option>
  )
}
ReactDOM.render(<SelectFrom />, document.getElementById('roo

select multiple 多选实现

 

4、处理多个输入

当需要处理多个 input 元素时,我们可以给每个元素添加 name 属性,并让处理函数根据 event.target.name 的值选择要执行的操作

class MoreInput extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: "",
      age: "",
      check: true
    }
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this)
  }

  handleChange(event) {
    let target = event.target;
    let name = target.name;
    console.log(target.checked)
    let value = target.name == 'check' ? target.checked : target.value
    this.setState({
      [name]: value
    })
  }

  handleSubmit(event) {
    console.log('提交:' + JSON.stringify(this.state))
    event.preventDefault()
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          姓名:<input type="text" value={this.state.name} onChange={this.handleChange} name="name" />
        </label>
        <br />
        <label>
          年龄:<input type="text" value={this.state.age} onChange={this.handleChange} name="age" />
        </label>
        <br />
        <label>
          选择:<input type="checkbox" checked={this.state.check} onChange={this.handleChange} name="check" />
        </label>
        <br />
        <label>
          <input type="submit" value="提交" />
        </label>
      </form>
    )
  }
}
ReactDOM.render(<MoreInput />, document.getElementById('root

5、受控组件输入空值

在受控组件上指定 value 的 prop 会阻止用户更改输入。如果你指定了 value,但输入仍可编辑,则可能是你意外地将value 设置为 undefined 或 null

ReactDOM.render(<input value="h" />, mountNode);
setTimeout(function() {
  ReactDOM.render(<input value={null} />, mountNode);
}, 1000);

6、非受控组件

受控组件表单数据是由React组件来管理的。非受控组件表单数据由DOM节点处理。

1)使用ref来从DOM 节点中获取表单数据

class NameRefForm extends React.Component {
  constructor(props) {
    super(props)
    this.handleSubmit = this.handleSubmit.bind(this)
    this.input = React.createRef()
  }
  handleSubmit(event) {
    console.log(this.input.current.value)
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          姓名:<input type="text" ref={this.input} />
        </label>
        <input type='submit' value="提交" />
      </form>
    )
  }
}


ReactDOM.render(<NameRefForm />, document.getElementById('roo

2)默认值

在非受控组件赋予组件一个初始值可以使用defaultValue属性而不是value。

checkbox、radio支持defaultChecked;select、textarea支持defaultValue。

<input defaultValue="Roman" type="text" ref={this.input} />

 

3)文件input标签

<input type="file" />始终是非受控组件。文件input标签的value是只读的,值只能用户设置而不能通过代码控制。

使用ref实现提交表单获取文件信息:

class FileInput extends React.Component {
  constructor(props) {
    super(props);
    this.file = React.createRef();
    this.handleSubmit = this.handleSubmit.bind(this)
  }


  handleSubmit(event) {
    console.log(this.file.current.files[0].name)
    event.preventDefault()
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>file:
          <input ref={this.file} type="file" />
        </label>
        <br />
        <input type="submit" value="submit" />
      </form>
    )
  }
}
ReactDOM.render(<FileInput />, document.getElementById('root')

其他

4、表单实现可以使用Formik

如果想寻找包含验证、追踪访问字段以及处理表单提交的完整解决方案,用 Formik 是不错的选择。然而,它也是建立在受控组件和管理 state 的基础之上 —— 所以不要忽视学习它们。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值