freeCodeCamp刷题笔记之React

目录

创建单个元素

创建多个元素

在JSX里添加注释

渲染 HTML 元素为 DOM 树

在 JSX 中定义一个 HTML Class

创建一个类式组件

使用 React 渲染嵌套组件

传递一个数组作为 Props

使用默认的 Props

覆盖默认的 Props

使用 PropTypes 来定义 Props 的类型

无状态函数组件的 Props

创建一个有状态的组件

在用户界面中渲染状态

使用state切换元素

写一个简单的计数器

创建可控制的输入框

创建一个可以控制的表单

将 State 作为 Props 传递给子组件

传递回调作为 Props(重点)

添加/移除事件侦听器

使用 shouldComponentUpdate 优化重新渲染

答案之书

if/else进行条件渲染

使用&&书写更简洁的条件

多元表达式进行条件渲染

根据组件状态修改内联样式

渲染多个组件


创建单个元素

const JSX=<div>Hello JSX!</div>

创建多个元素

需要用div包裹起来

const JSX=(
    <div>
      <p>Paragraph One</p>
      <p>Paragraph Two</p>
      <p>Paragraph Three</p>
    </div>
);

在JSX里添加注释

const JSX=(
    <div>
        <p>Paragraph One</p>
        <p>Paragraph Two</p>
        <p>Paragraph Three</p>
        {/* Hello JSX*/}
    </div>
);

渲染 HTML 元素为 DOM 树

ReactDOM.render(JSX,document.getElementById('root'))

在 JSX 中定义一个 HTML Class

JSX 中所有 HTML 属性和事件引用的命名约定都变成了驼峰式。

const JSX = (
  <div className="myDiv">
    <h1>Add a class to this div</h1>
  </div>
);

创建一个类式组件

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
   return(
      <div>
        <h1>Hello React!</h1>
      </div>
   )
  }
};

使用 React 渲染嵌套组件

组件组合是 React 的强大功能之一。 当使用 React 时,应当先用组件的思路考虑清楚用户界面的结构(如上一个挑战中的 App 示例)。 可以将 UI 分解为基本的构建块,这些构建块就是组件。 这样做有助于将负责 UI 的代码与负责处理应用程序逻辑的代码分开, 并可以大大简化复杂项目的开发和维护。

const TypesOfFruit = () => {
  return (
    <div>
      <h2>Fruits:</h2>
      <ul>
        <li>Apples</li>
        <li>Blueberries</li>
        <li>Strawberries</li>
        <li>Bananas</li>
      </ul>
    </div>
  );
};

const Fruits = () => {
  return (
    <div>
      <TypesOfFruit />
    </div>
  );
};

class TypesOfFood extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <div>
        <h1>Types of Food:</h1>
        <Fruits />
      </div>
    );
  }
};

传递一个数组作为 Props

const List = (props) => {
  return <p>{props.tasks.join(", ")}</p>
};

class ToDo extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <div>
        <h1>To Do Lists</h1>
        <h2>Today</h2>
        <List tasks={['To Do Lists',' Today']}/>
        <h2>Tomorrow</h2>
        <List tasks={['To Do Lists',' Today',' 222']}/>
      </div>
    );
  }
};

使用默认的 Props

const ShoppingCart = (props) => {
  return (
    <div>
      <h1>Shopping Cart Component</h1>
    </div>
  )
};
ShoppingCart.defaultProps = {
  items: 0
};

覆盖默认的 Props

const Items = (props) => {
  return <h1>Current Quantity of Items in Cart: {props.quantity}</h1>
}

Items.defaultProps = {
  quantity: 10
}

class ShoppingCart extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return <Items quantity={10} />
  }
};

使用 PropTypes 来定义 Props 的类型

PropTypes 提供一系列验证器,可用于确保组件接收到的数据类型是有效的。当传入的 prop 值类型不正确时,JavaScript 控制台将会显示警告。出于性能方面的考虑,propTypes 仅在开发模式下进行检查。

详细说明请看官网

const Items = (props) => {
  return <h1>Current Quantity of Items in Cart: {props.quantity}</h1>
};

Items.propTypes={
  // 解释下为什么上面用小写开头下面用大写
  quantity:PropTypes.number.isRequired
}

class ShoppingCart extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return <Items />
  }
};

无状态函数组件的 Props

无状态函数组件是一个函数,它接收 props 作为输入并返回 JSX。 另一方面,无状态组件是一个类,它扩展了React.Component,但是不使用内部状态。 最后,状态组件是指维护其自身内部状态的组件, 它简称组件或 React 组件。一种常见的应用模式是尽可能减少状态组件并创建无状态的函数组件。 这有助于将状态管理包含到应用程序的特定区域。 反过来,通过更容易地跟踪状态变化如何影响其行为,可以改善应用程序的开发和维护。

class CampSite extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <div>
        <Camper/>
      </div>
    );
  }
};
// 无状态函数组件
const Camper = props => <p>{props.name}</p>

Camper.defaultProps={
  name: 'CamperBot'
}
Camper.propTypes={
  name: PropTypes.string.isRequired
}
ReactDOM.render(<CampSite />,document.getElementById('root'))

创建一个有状态的组件

class StatefulComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state={
      name:'lvlan'
    }
  }
  render() {
    return (
      <div>
        <h1>{this.state.name}</h1>
      </div>
    );
  }
};

在用户界面中渲染状态

在 render() 方法中,在 return 语句之前,可以直接编写 JavaScript。 例如,可以声明函数、从 state 或 props 中访问数据、对此数据执行计算等。 然后,可以将任何数据赋值给 return 语句中可以访问的变量。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: 'freeCodeCamp'
    }
  }
  render() {
    const {name} =this.state;
    return (
      <div>
        <h1>{name}</h1>
      </div>
    );
  }
};

有几种方法可以让类方法访问 this。一种常见的方法是在构造函数中显式地绑定 this,这样当组件初始化时,this 就会绑定到类方法。

this.handleClick=this.handleClick.bind(this)

使用state切换元素

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      visibility: false
    };
    this.toggleVisibility=this.toggleVisibility.bind(this)
  }
  toggleVisibility(){
    this.setState(state => ({
      visibility: !state.visibility
    }))
  }
  render() {
    if (this.state.visibility) {
      return (
        <div>
          <button onClick={this.toggleVisibility}>Click Me</button>
          <h1>Now you see me!</h1>
        </div>
      );
    } else {
      return (
        <div>
          <button onClick={this.toggleVisibility}>Click Me</button>
        </div>
      );
    }
  }
}

写一个简单的计数器

这里多注意一下更改状态的写法,一个参数、两个参数、无参数的写法

class Counter extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        count: 0
      };
      this.increment=this.increment.bind(this)
      this.decrement=this.decrement.bind(this)
      this.reset=this.reset.bind(this)
    }
    increment(){
        this.setState(state=>({
            count:state.count+1
        }))
    }
    decrement(){
        this.setState(state=>({
            count:state.count-1
        }))
    }
    reset(){
        this.setState({
            count:0
        })
    }
    render() {
      return (
        <div>
          <button className='inc' onClick={this.increment}>Increment!</button>
          <button className='dec' onClick={this.decrement}>Decrement!</button>
          <button className='reset' onClick={this.reset}>Reset</button>
          <h1>Current Count: {this.state.count}</h1>
        </div>
      );
    }
  };

创建可控制的输入框

class ControlledInput extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        input: ''
      };
      this.handleChange=this.handleChange.bind(this)
    }
    handleChange(event){
        this.setState({
            input:event.target.value
        })
    }
    render() {
      return (
        <div>
          <h4>Controlled Input:</h4>
          {/* 也可以写成 onChange={this.handleChange.bind(this)}*/}
          <input value={this.state.input} onChange={this.handleChange} />
          <p>{this.state.input}</p>
        </div>
      );
    }
  };

创建一个可以控制的表单

class MyForm extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        input: '',
        submit: ''
      };
      this.handleChange = this.handleChange.bind(this);
      this.handleSubmit = this.handleSubmit.bind(this);
    }
    handleChange(event) {
      this.setState({
        input: event.target.value
      });
    }
    handleSubmit(event) {
      event.preventDefault();
      this.setState({
        submit: this.state.input
      });
    }
    render() {
      return (
        <div>
          <form onSubmit={this.handleSubmit}>
            <input type="text" value={this.state.input} onChange={this.handleChange} />
            <button type='submit'>Submit!</button>
          </form>
          <h1>{this.state.submit}</h1>
        </div>
      );
    }
  }

将 State 作为 Props 传递给子组件

class MyApp extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        name: 'CamperBot'
      }
    }
    render() {
      return (
         <div>
           <Navbar name={this.state.name} />
         </div>
      );
    }
  };
  
  class Navbar extends React.Component {
    constructor(props) {
      super(props);
    }
    render() {
      return (
      <div>
        <h1>Hello, my name is: {this.props.name}</h1>
      </div>
      );
    }
  };

传递回调作为 Props(重点)

可以将 state 作为 props 传递给子组件,但不仅限于传递数据。 也可以将函数或在 React 组件中定义的任何方法传递给子组件。 这就是子组件与父组件交互的方式。 可以把方法像普通 prop 一样传递给子组件, 它会被分配一个名字,可以在子组件中的 this.props 下访问该方法的名字。

// 父组件
class MyApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      inputValue: ''
    }
    this.handleChange = this.handleChange.bind(this);
  }
  // 方法写在父组件
  handleChange(event) {
    this.setState({
      inputValue: event.target.value
    });
  }
  render() {
    return (
       <div>
          <GetInput
           input={this.state.inputValue}
           handleChange={this.handleChange}/>
           {/* 通过方法名传递*/}
          <RenderInput
           input={this.state.inputValue}/>
       </div>
    );
  }
};

class GetInput extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <div>
        <h3>Get Input:</h3>
        <input
          value={this.props.input}
          onChange={this.props.handleChange}/>
      </div>
    );
  }
};

class RenderInput extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <div>
        <h3>Input Render:</h3>
        <p>{this.props.input}</p>
      </div>
    );
  }
};

添加/移除事件侦听器

在 componentWillUnmount() 中移除相同的事件监听器。 可以把相同的参数传递给 document.removeEventListener()。 在卸载和销毁 React 组件之前,最好在这个生命周期方法中对它们进行清理。 移除事件监听器就是这样一个清理操作的例子。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      message: ''
    };
    this.handleEnter = this.handleEnter.bind(this);
    this.handleKeyPress = this.handleKeyPress.bind(this);
  }
  componentDidMount() {
    document.addEventListener("keydown", this.handleKeyPress);
  }
  componentWillUnmount() {
    document.removeEventListener("keydown", this.handleKeyPress);
  }
  handleEnter() {
    this.setState((state) => ({
      message: state.message + 'You pressed the enter key! '
    }));
  }
  handleKeyPress(event) {
    if (event.keyCode === 13) {
      this.handleEnter();
    }
  }
  render() {
    return (
      <div>
        <h1>{this.state.message}</h1>
      </div>
    );
  }
};

使用 shouldComponentUpdate 优化重新渲染

class OnlyEvens extends React.Component {
  constructor(props) {
    super(props);
  }
  shouldComponentUpdate(nextProps, nextState) {
    console.log('Should I update?');
    // 拿到下一次props.value的值来判断是否重新渲染
    if(nextProps.value % 2 == 0){
      return true;
    }
    return false;
  }
  componentDidUpdate() {
    console.log('Component re-rendered.');
  }
  render() {
    return <h1>{this.props.value}</h1>;
  }
}

class Controller extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: 0
    };
    this.addValue = this.addValue.bind(this);
  }
  addValue() {
    this.setState(state => ({
      value: state.value + 1
    }));
  }
  render() {
    return (
      <div>
        <button onClick={this.addValue}>Add</button>
        <OnlyEvens value={this.state.value} />
      </div>
    );
  }
}

答案之书

const inputStyle = {
  width: 235,
  margin: 5
};

class MagicEightBall extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      userInput: '',
      randomIndex: ''
    };
    this.ask = this.ask.bind(this);
    this.handleChange = this.handleChange.bind(this);
  }
  ask() {
    if (this.state.userInput) {
      this.setState({
        randomIndex: Math.floor(Math.random() * 20),
        userInput: ''
      });
    }
  }
  handleChange(event) {
    this.setState({
      userInput: event.target.value
    });
  }
  render() {
    const possibleAnswers = [
      'It is certain',
      'It is decidedly so',
      'Without a doubt',
      'Yes, definitely',
      'You may rely on it',
      'As I see it, yes',
      'Outlook good',
      'Yes',
      'Signs point to yes',
      'Reply hazy try again',
      'Ask again later',
      'Better not tell you now',
      'Cannot predict now',
      'Concentrate and ask again',
      "Don't count on it",
      'My reply is no',
      'My sources say no',
      'Most likely',
      'Outlook not so good',
      'Very doubtful'
    ];
    const answer = possibleAnswers[this.state.randomIndex];
    return (
      <div>
        <input
          type='text'
          value={this.state.userInput}
          onChange={this.handleChange}
          style={inputStyle}
        />
        <br />
        <button onClick={this.ask}>Ask the Magic Eight Ball!</button>
        <br />
        <h3>Answer:</h3>
        <p>
          {answer}
        </p>
      </div>
    );
  }
}

if/else进行条件渲染

class MyComponent extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        display: true
      }
      this.toggleDisplay = this.toggleDisplay.bind(this);
    }
    toggleDisplay() {
      this.setState((state) => ({
        display: !state.display
      }));
    }
    render() {
      if(this.state.display){
        return (
         <div>
           <button onClick={this.toggleDisplay}>Toggle Display</button>
           <h1>Displayed!</h1>
         </div>
        );
      } else {
        return (
            <div>
            <button onClick={this.toggleDisplay}>Toggle Display</button>
            </div>
        );
      }
    }
};

使用&&书写更简洁的条件

 class MyComponent extends React.Component {
  ...
  render() {
    return (
       <div>
         <button onClick={this.toggleDisplay}>Toggle Display</button>
         {this.state.display && <h1>Displayed!</h1>}
       </div>
    );
  }
};

多元表达式进行条件渲染

const inputStyle = {
    width: 235,
    margin: 5
};

class CheckUserAge extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            input: '',
            userAge: ''
        };
        this.submit = this.submit.bind(this);
        this.handleChange = this.handleChange.bind(this);
    }
    handleChange(e) {
        this.setState({
            input: e.target.value,
            userAge: ''
        });
    }
    submit() {
        this.setState(state => ({
            userAge: state.input
        }));
    }
    render() {
        const buttonOne = <button onClick={this.submit}>Submit</button>;
        const buttonTwo = <button>You May Enter</button>;
        const buttonThree = <button>You Shall Not Pass</button>;
        return (
            <div>
                <h3>Enter Your Age to Continue</h3>
                <input
                    style={inputStyle}
                    type='number'
                    value={this.state.input}
                    onChange={this.handleChange}
                />
                <br />
                {/* 说白了表达式比条件永远多1个 */}
                {
                    this.state.userAge === '' ? buttonOne : this.state.userAge >= 18 ? buttonTwo : buttonThree
                }
            </div>
        );
    }
}

根据组件状态修改内联样式

class GateKeeper extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            input: ''
        };
        this.handleChange = this.handleChange.bind(this);
    }
    handleChange(event) {
        this.setState({ input: event.target.value })
    }
    render() {
        let inputStyle = {
            border: '1px solid black'
        };
        if (this.state.input.length > 15) {
            inputStyle.border = '3px solid red'
        }
        return (
            <div>
                <h3>Don't Type Too Much:</h3>
                <input
                    type="text"
                    style={inputStyle}
                    value={this.state.input}
                    onChange={this.handleChange} />
            </div>
        );
    }
};

渲染多个组件

const frontEndFrameworks = [
    'React',
    'Angular',
    'Ember',
    'Knockout',
    'Backbone',
    'Vue'
];

function Frameworks() {
    const renderFrameworks = frontEndFrameworks.map(i => <li key={i}>{i}</li>);
    return (
        <div>
            <h1>Popular Front End JavaScript Frameworks</h1>
            <ul>
                {renderFrameworks}
            </ul>
        </div>
    );
};
上一篇:freeCodeCamp刷题笔记之Redux


下一篇:前端基础学习资源