zoukankan      html  css  js  c++  java
  • React文档总结

    元素渲染

    更新元素渲染

    计时器例子

    function tick(){
      const element = (
        <div>
          <h1>Hello, World!</h1>
          <h2>It is {new Date().toLocaleTimeString()}.</h2>
        </div>
      );
    
    ReactDOM.render(
      element, 
      document.getElementById('root')
    );
    }
    setInterval(tick, 1000)
    

    react只会更新必要的部分,上面计时器的例子中,只会更新时间,而element中的Hello, World等则不会更新。

    组建 & Props

    自定义组件

    自定义组件包括函数定义组件和类定义组件,下面例子中两种定义的效果是相同的。

    // 函数定义组件
    // function Welcome(props){
    //   return <h1>Hello, {props.name}</h1>;
    // }
    
    // 类定义组件
    class Welcome extends React.Component {
      render() {
        return <h1>Hello, {this.props.name}</h1>;
      }
    }
    
    const element = <Welcome name="Sarah" />;
    
    ReactDOM.render(
      element, 
      document.getElementById('root')
    );
    

    组合组件

    组件可以在返回值中引用其它组件,从而实现组件之间的组合。

    // 类定义组件
    class Welcome extends React.Component {
      render() {
        return <h1>Hello, {this.props.name}</h1>;
      }
    }
    
    class App extends React.Component {
      render(){
        return (
          <div>
            <Welcome name='Sarah' />
            <Welcome name='Lily' />
            <Welcome name='Dency' />
          </div>
        );
      }
    }
    
    ReactDOM.render(
      <App />, 
      document.getElementById('root')
    );
    

    提取组件

    通过提取组件可以将一个大的组件拆分成由许多小的组件合并而成。

    原始组件:

    function Comment(props) {
      return (
        <div className="Comment">
          <div className="UserInfo">
            <img className="Avater"
              src={props.author.avatarUrl}
              alt={props.author.name}
            />
            <div className="UserInfo-name">
              {props.author.name}
            </div>
          </div>
          <div className="Comment-text">
            {props.text}
          </div>
          <div className="Comment-data">
            {formatData(props.date)}
          </div>
        </div>
      );
    }
    

    拆分后:

    // Avater组件
    function Avater(props) {
      return (
        <img className="Avater" 
          src={props.user.avatarUrl}
          alt={props.user.name}
        />
      );
    }
    // UserInfo组件
    function UserInfo(props) {
      return (
        <div className="UserInfo">
          <Avater user={props.author} />
          <div className="UserInfo-name">
            {props.user.name}
          </div>
        </div>
      );
    }
    // 修改后的Comment
    function Comment(props) {
      return (
        <div className="Comment">
          <UserInfo author={props.author} />
          <div className="Comment-text">
            {props.text}
          </div>
          <div className="Comment-data">
            {formatData(props.date)}
          </div>
        </div>
      );
    }
    

    Props只能用来读取,不能被修改。

    State & 生命周期

    生命周期

    用组件的生命周期改写上面的计时器功能

    class Clock extends React.Component{
      constructor(props) {
        super(props);
        this.state = {date: new Date()};
      }
    
      // 组件插入到DOM中启动定时器
      componentDidMount() {
        this.timerID = setInterval(
          () => this.tick(),
          1000
        );
      }
    
      // 组件移出DOM时去除定时器
      componentWillMount() {
        clearInterval(this.timerID);
      }
    
      tick(){
        this.setState({
          date: new Date()
        });
      }
    
      render(){
        return (
          <div>
            <h1>Hello, World!</h1>
            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
          </div>
        );
      }
    }
    
    ReactDOM.render(
      <Clock />, 
      document.getElementById('root')
    );
    

    正确使用状态

    不可直接更新状态

    以下代码不会重新渲染组件

    this.state.comment = "Hello"
    

    应当使用setState

    状态更新可能是异步的

    React可以将多个setState()调用合并成一个调用来提高性能。所以状态更新是异步的,不能根据上一个状态值来计算下一个状态值。

    // Wrong
    this.setState({
    	counter: this.state.counter + this.props.increment,
    });
    
    // Correct
    this.setState((prevState, props) => ({
    	counter: prevState.counter + props.increment
    }));
    
    // Correct
    this.setState(function(prevState, props) {
    	return (
    		counter: prevState.counter + props.increment
    	);
    });
    

    事件处理

    React事件绑定属性命名采用驼峰写法,需要传入一个事件处理函数,而不是一个字符串。

    // HTML
    <button onclick="activateLasers()">
    	Activate Lasers
    </button>
    
    // React
    <button onClick={activateLasers}>
    	Activate Lasers
    </button>
    

    在React中不能使用返回false的方式阻止默认行为,而要使用preventDefault。

    // HTML
    <a href="#" onclick="console.log('The link was clicked.'); return false">
    	Click me
    </a>
    
    function ActionLink() {
    function handleClick(e) {
    	e.preventDefault();
    	console.log('The link was clicked.');
    }
    return (
    	<a href="#" onClick={handleClick}>
    		Click me
    	</a>
    );
    }
    

    使用this绑定点击事件

    class Toggle extends React.Component {
      constructor(props){
        super(props);
        this.state = {
          isToggleOn: true
        };
        // This blinding is necessary to make `this` work in the callback
        this.handleClick = this.handleClick.bind(this);
      }
    
      handleClick() {
        this.setState(prevState => ({
          isToggleOn: !prevState.isToggleOn
        }));
      }
    
      render(){
        return (
          <button onClick={this.handleClick}>
            {this.state.isToggleOn ? 'ON' : 'OFF'}
          </button>
        );
      }
    }
    
    ReactDOM.render(
      <Toggle />, 
      document.getElementById('root')
    );
    

    使用如下两种写法可以不用使用bind绑定this

      handleClick = () => {
        this.setState(prevState => ({
          isToggleOn: !prevState.isToggleOn
        }));
      }
    
      render(){
        return (
          <button onClick={(e) => this.handleClick(e)}>
            {this.state.isToggleOn ? 'ON' : 'OFF'}
          </button>
        );
      }
    

    向事件处理程序传递参数

    有两种方式可以向事件处理程序传递参数

    <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
    <button onClick={this.deletdRow.bind(this, id)}>Delete Row</button>
    

    下面例子使用bind()传递参数

    class Popper extends React.Component{
      constructor(){
        super();
        this.state = {name:'Hello world'};
      }
    
      preventPop(name, e){  // 事件对象e要放在最后
        e.preventDefault();
        alert(name);
      }
    
      render(){
        return (
          <div>
            <p>hello</p>
            {/* Pass params via bind() method. */}
            <a href="http://reactjs.org" onClick={this.preventPop.bind(this, this.state.name)}>Click</a>
          </div>
        );
      }
    }
    
    ReactDOM.render(
      <Popper />, 
      document.getElementById('root')
    );
    

    条件渲染

    与运算符 &&

    function Mailbox(props) {
      const unreadMessages = props.unreadMessages;
      return (
        <div>
          <h1>Hello!</h1>
          {unreadMessages.length > 0 &&
            <h2>
              You have {unreadMessages.length} unread message.
            </h2>
          }
        </div>
      );
    }
    
    const message = ['React', 'Re: React', 'Re:Re: React']
    
    ReactDOM.render(
      <Mailbox unreadMessages={message} />, 
      document.getElementById('root')
    );
    

    在JavaScript中,true && expression 总是返回expression,而 false && expression 总是返回false。

    阻止组件渲染

    function WarningBanner(props) {
      if(!props.warn) {
        return null;
      }
    
      return (
        <div className="warning">
          Warning!
        </div>
      );
    }
    
    class Page extends React.Component {
      constructor(props) {
        super(props);
        this.state = {showWarning: true}
        this.handleToggleClick = this.handleToggleClick.bind(this);
      }
    
      handleToggleClick() {
        this.setState(prevState => ({
          showWarning: !prevState.showWarning
        }));
      }
    
      render() {
        return (
          <div>
            <WarningBanner warn={this.state.showWarning} />
            <button onClick={this.handleToggleClick}>
              {this.state.showWarning ? 'Hide' : 'Show'}
            </button>
          </div>
        );
      }
    }
    
    ReactDOM.render(
      <Page />, 
      document.getElementById('root')
    );
    

    列表 & Keys

    渲染多个组件

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

    基础列表组件

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

    注意,如果不加key属性,会得到一个警告 a key should be provided for list items。意思是每个列表元素都应该分配一个确定的标识。

    Keys

    一个元素的key最好是这个元素在列表中拥有的独一无二的字符串。通常我们使用来自数据的id作为元素的key。

    const todoItems = todos.map((todo) => 
    	<li key={todo.id}>
    		{todo.text}
    	</li>
    );
    

    当元素没有确定的id时,可以使用它的序列号索引index作为key

    const todoItems = todos.map((todo, index) => 
      // Only do this if items have no stable IDs
      <li key={index}>
        {todo.text}
      </li>
    );
    

    元素的key在他的兄弟元素之间应该唯一,但是不需要全局唯一,也就是说不同列表的元素可以使用相同的key。
    key会作为React的提示,但是不会传递给组件。如果组件中需要使用和key相同的值,可将其作为属性传递:

    // Post组件可以读出props.id, 但是不能读出props.key
    const content = posts.map((post) => 
    	<Post
    		key={post.id}
    		id={post.id}
    		title={post.title}
    	 />
    );
    

    表单

    select

    class FlavorForm extends React.Component {
      constructor(props) {
        super(props);
        this.state = { value: 'coconut' };
    
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
      }
    
      handleChange(event) {
        this.setState({value: event.target.value});
      }
    
      handleSubmit(event) {
        alert('Your favorite flavor is: ' + this.state.value);
        event.preventDefault();
      }
    
      render() {
        return (
          <form onSubmit={this.handleSubmit}>
            <label>
              Pick your favorite La Croix flavor:
              <select value={this.state.value} onChange={this.handleChange}>
                <option value="grapefruit">grapefruit</option>
                <option value="lime">Lime</option>
                <option value="coconut">Coconut</option>
                <option value="mango">Mango</option>
              </select>
            </label>
            <input type="submit" value="submit" />
          </form>
        );
      }
    }
    
    ReactDOM.render(
      <FlavorForm />,
      document.getElementById('root')
    );
    

    在React中并不使用之前的selected属性,而是在根select标签上用value来表示选中项。

    多个输入

    class Reservation extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          isGoing: true,
          numberOfGuests: 2
        };
    
        this.handleInputChange = this.handleInputChange.bind(this);
      }
    
      handleInputChange(event) {
        const target = event.target;
        const value = target.type === 'checkbox' ? target.checked : target.value;
        const name = target.name;
    
        this.setState({
          [name]: value
        });
      }
    
      render() {
        return (
          <form>
            <label>
              Is going:
              <input 
                name="isGoing"
                type="checkbox"
                checked={this.state.isGoing}
                onChange={this.handleInputChange}
              />
            </label>
            <br />
            <label>
              Number of Guests:
              <input
                name="numberOfGuests"
                type="number"
                value={this.state.numberOfGuests}
                onChange={this.handleInputChange} />
            </label>
          </form>
        );
      }
    }
    
    ReactDOM.render(
      <Reservation />,
      document.getElementById('root')
    );
    

    上面通过给元素一个name属性,让函数根据event.target.name的值来选择做什么,这样就可以在一个处理函数中处理多个input元素。

    状态提升

    状态提升是指多个组件共用一个值时,每次改变值时不进行双向绑定,而是将该值提升到上一级的共同组件中。

    组合 VS 继承

    包含关系

    使用children属性将子元素直接传递到输出。

    function FancyBorder(props) {
      return (
        <div className={'FancyBorder FancyBorder-' + props.color}>
          {props.children}
        </div>
      );
    }
    
    function WelcomeDialog() {
      return (
        <FancyBorder color="blue">
          <h1 className="Dialog-title">
            Welcome
          </h1>
          <p className="Dialog-message">
            Thank you for visiting our spacecraft!
          </p>
        </FancyBorder>
      );
    }
    
    ReactDOM.render(
      <WelcomeDialog />,
      document.getElementById('root')
    );
    

    除此之外,也可以使用自己约定的属性,在组件中需要多个入口的情况下非常有用。

    function SplitPane(props) {
      return (
        <div className="SplitPane">
          <div className="SplitPane-left">
            {props.left}
          </div>
          <div className="SplitPane-right">
            {props.right}
          </div>
        </div>
      );
    }
    
    function App() {
      return (
        <SplitPane left={<Contacts />} right={<Chat />} />
      );
    }
    
    ReactDOM.render(
      <App />,
      document.getElementById('root')
    );
    

    特殊实例

    一个组件可以是另一个组件的实例。

    function FancyBorder(props) {
      return (
        <div className={'FancyBorder FancyBorder-' + props.color}>
          {props.children}
        </div>
      );
    }
    
    function Dialog(props) {
      return(
        <FancyBorder color="blue">
          <h1 className="Dialog-title">
            {props.title}
          </h1>
          <p className="Dialog-message">
            {props.message}
          </p>
        </FancyBorder>
      );
    }
    
    function WelcomeDialog() {
      return (
        <Dialog
          title="Welcome"
          message="Thakn you for visiting our spacecraft!"
        />
      );
    }
    
    ReactDOM.render(
      <WelcomeDialog />,
      document.getElementById('root')
    );
    

    组合对于定义类的组件同样适用。

    function FancyBorder(props) {
      return (
        <div className={'FancyBorder FancyBorder-' + props.color}>
          {props.children}
        </div>
      );
    }
    
    function Dialog(props) {
      return(
        <FancyBorder color="blue">
          <h1 className="Dialog-title">
            {props.title}
          </h1>
          <p className="Dialog-message">
            {props.message}
          </p>
        </FancyBorder>
      );
    }
    
    class SignUpDialog extends React.Component {
      constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
        this.handleSignUp = this.handleSignUp.bind(this);
        this.state = {login: ''};
      }
    
      render() {
        return (
          <Dialog title="Mars Exploration Program"
                  message="How should we refer to you?">
            <input value={this.state.login} onChange={this.handleChange} />
            <button onClick={this.handleSignUp}>
              Sign Me Up!
            </button>
          </Dialog>
        );
      }
    
      handleChange(e) {
        this,this.setState({login: e.target.value});
      }
    
      handleSignUp() {
        alert(`Welcome aboard, ${this.state.login}!`);
      }
    }
    
    ReactDOM.render(
      <SignUpDialog />,
      document.getElementById('root')
    );
    
  • 相关阅读:
    珠海洪锐在线监测agent_linux系统
    python中的不定长参数
    记一次刻苦铭心得安装zabbix经历
    狼书第三章Jinja2模板总结
    关于消息闪现的问题
    了解HTTP状态码
    关于用Flask建立一个简单的web应用
    将模块安装到Site-packages
    在Centos6中安装python3.6
    unity 生成缩略图 , 图片缩放
  • 原文地址:https://www.cnblogs.com/suraer/p/9171625.html
Copyright © 2011-2022 走看看