react学习笔记

2020-11-11  本文已影响0人  三天两觉_

react学习

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />,document.getElementById('root'));

ReactDOM的render函数可以把App组件挂载到id为root的节点下。
注意一定要引入react包,<App/>是一个jsx语法,需要依赖react包去进行编译。

jsx语法

jsx中如果要使用自己创建的组件,组件一定要以大写开头
想要在jsx中访问state中的数据或者写表达式都要用{}

响应式设计思想和事件绑定

<button onClick={this.handleBtnClick.bind(this)}>提交</button>
    handleItemDelete(index) {
        //禁止使用
        this.state.list.splice(index,1);
        //推荐使用
        const list = [...this.state.list];
        list.splice(index, 1);
        this.setState({
        list,
        });
    }

jsx语法细节补充

<ul>
    {this.state.list.map((item, index) => {
    return (
    <li key={index} dangerouslySetInnerHTML={{__html:item}}></li>
    );
    })}
</ul>

父子组件通信

react衍生出的思考

state、props和render之间的关系

了解虚拟DOM

深入了解虚拟DOM

render(){
  return <div class="list-item">item</div>
}
//等价于下面
render(){
  return react.createElement("div",{className:"list-item"},"item")
}
render(){
  return <div><span>item</span><div>
}
//等价于下面
render(){
  return React.createElement("div",{},React.createElement("span",{},"item"));
}

react中的diff算法

//假如说用index作为key值
//旧的dom结构
a 0
b 1
c 2
//删除a节点 新的dom结构
b 0 
c 1
//此时key就乱了 0和1所代表的的结构和旧的dom结构不一样了
//假如直接用内容本身(假设内容不重复)作为key值
//旧的dom结构
a a
b b
c c
//删除a 新的dom结构
b b
c c
//此时b和c代表的dom结构和旧的dom结构是一样的,大大提升了比对的性能。

ref

this.setState((prevState)=>{},()=>{
  //第二个回调函数会在更新完真实dom之后被触发。
})

生命周期函数

//1.shouldComponentUpdate 组件是否需要被更新,返回一个bool类型的值
//当父组件render执行的时候,子组件的render也会被执行,但有时候子组件并没有变化,不需要执行,所以可以通过shouldComponentUpdate控制
shouldComponentUpdate(nextProps,nextState){
  if(nextProps.content!==this.props.content){
      return true;
  }else{
      return false
  }
}
//2.如果组件需要被更新会依次执行componentWillUpdate=>render=>componentDidUpdate

//3.componentWillReceiveProps是props改变的时候子组件才有可能执行,满足以下条件才会被执行
/*
  1)接收了父组件传过来的数据
  2)父组件的render函数触发了
    a.如果子组件是第一次存在于父组件中,则不会执行
    b.如果子组件不是第一次存在于父组件中,则会执行
*/

发送ajax请求的时机

redux

export const CHANGE_INPUT_VAL = "change_input_val";
export const ADD_TODO_ITEM = "add_todo_item";
export const DEL_TODO_ITEM = "del_todo_item";
const defaultState = {
    inputVal:"",
    list:["春花秋月何时了","往事知多少"]
}
import { CHANGE_INPUT_VAL,ADD_TODO_ITEM,DEL_TODO_ITEM } from "./actionTypes";
//reducer是一个函数,返回一个新对象;不能直接修改state中的值
export default (state=defaultState,action)=>{
    if(action.type==CHANGE_INPUT_VAL){
        const newState = JSON.parse(JSON.stringify(state));
        newState.inputVal = action.value;
        return newState;
    }else if(action.type==ADD_TODO_ITEM){
        const newState = JSON.parse(JSON.stringify(state));
        newState.list.push(state.inputVal);
        newState.inputVal = "";
        return newState;
    }else if(action.type==DEL_TODO_ITEM){
        const newState = JSON.parse(JSON.stringify(state));
        newState.list.splice(action.index,1);
        return newState;
    }
    return state;
}
import { ADD_TODO_ITEM,DEL_TODO_ITEM,CHANGE_INPUT_VAL } from "./actionTypes";
export const getAddTodoItemAction = ()=>({
    type:ADD_TODO_ITEM
})
export const getDelTodoItemAction = (index)=>({
    type:DEL_TODO_ITEM,
    index
})
export const getChangeInputValAction = (value)=>({
    type:CHANGE_INPUT_VAL,
    value
})
import { getAddTodoItemAction,getChangeInputValAction,getDelTodoItemAction } from "./store/actionCreators";

class TodoList extends Component {
  constructor(props) {
    super(props);
    this.state = store.getState();
    this.addTodoItem = this.addTodoItem.bind(this);
    this.changeInputVal = this.changeInputVal.bind(this);
    this.handleStoreChange = this.handleStoreChange.bind(this);
  }
  componentDidMount(){
    /*订阅store变化 改变state中的值*/
    store.subscribe(this.handleStoreChange);
  }
  render(){
    return (
      <Search
        placeholder="请输入..."
        enterButton="添加"
        onChange={this.changeInputVal}
        onSearch={this.addTodoItem}
        value={this.state.inputVal}
      />
      <List
        bordered
        dataSource={this.state.list}
        renderItem={(item,index) => (
          <List.Item onClick={this.delTodoItem.bind(this,index)}>
            {item}
          </List.Item>
        )}
      />
    )
  }
  addTodoItem() {
    const action = getAddTodoItemAction();
    store.dispatch(action);
  }
  delTodoItem(index){
    const action = getDelTodoItemAction(index);
    store.dispatch(action);
  }
  changeInputVal(e) {
    const action = getChangeInputValAction(e.target.value);
    store.dispatch(action);
  }
  handleStoreChange(){
    this.setState(store.getState())
  }
}

ui组件和容器组件

class TodoListUI extends Component {
  render() {
    return (
      <div>
        <Row className="m-t20" justify="center">
          <Col span={8}>
            <Search
              placeholder="请输入..."
              enterButton="添加"
              onChange={this.props.changeInputVal}
              onSearch={this.props.addTodoItem}
              value={this.props.inputVal}
            />
          </Col>
        </Row>
        <Row className="m-t20" justify="center">
          <Col span={8}>
            <List
              bordered
              dataSource={this.props.list}
              renderItem={(item, index) => (
              //注意 此处想要调用父函数还传参数,可以在函数中调用父传过来的函数
                <List.Item onClick={()=>{this.props.delTodoItem(index)}}>
                  {item}
                </List.Item>
              )}
            />
          </Col>
        </Row>
      </div>
    );
  }
}
export default TodoListUI;
const TodoListUI = (props)=>{
  return (
     //此处是jsx代码
    //之前写的this.props就可以换成只写props。
    //普通组件是一个类,生成的对象有生命周期函数,还有render等;无状态组件就是一个函数,用来返回一段jsx,所以性能更快。
  )
}

在redux中使用发送异步请求获取数据

//可以在生命周期componentDidMount中发送异步ajax请求,然后改变store中的数据,最后更新state中的数据
componentDidMount() {
  /*订阅store变化*/
  store.subscribe(this.handleStoreChange);
  axios.get("/data/list.json").then(({data}) => {
    const action = getInitListAction(data)
    store.dispatch(action)
    this.setState(store.getState())
  });
}

redux-thank中间件(redux的中间件)实现ajax数据请求

export const getInitListAction = (list)=>({
    type:INIT_LIST,
    list
})
//action返回一个函数,配合redux-thunk使用。
export const getTodoList = ()=>{
    return (dispatch)=>{
        axios.get("/data/list.json").then(({data})=>{
            const action = getInitListAction(data);
            dispatch(action)
        })
    }
}
import {getTodoList} from "actionCreators";
componentDidMount(){
  const action = getTodoList();
  //调用store的dispatch方法,dispatch方法会自行判断传进来的action的类型,如果传入的action是一个对象,就会把对象传给store;如果是函数就会执行这个函数(配合中间件redux-thunk才能实现这个效果),函数实参是store的dispatch方法,再用dispatch派发action给store。
  store.dispatch(action);
}

redux中间件是什么

redux-saga入门

react-redux终章

//程序入口文件index.js代码
import {Provider} from "react-redux";
import TodoList from "./TodoList";
ReactDOM.render(
  <Provider store={store}>
    <TodoList />
  </Provider>,
  document.getElementById('root')
);
//Todolist.js代码
import {Component} from "react";
import {connect} from "react-redux";
class TodoList extends Component{
    constructor(props){
        super(props);
    }
    render(){
        return (
            <div>
                <input type="text" value={this.props.inputVal} onChange={this.props.changeInputVal}/>
                <button>提交</button>
                <ul>
                    <li>dell</li>
                </ul>
            </div>
        )
    }
}

☆☆☆☆☆☆☆☆接着上面的内容☆☆☆☆☆☆☆

//把store中的数据映射到props中,返回的对象就是映射到props中的值
const mapStateToProps = (state)=>{
    return {
        inputVal:state.inputVal
    }
}
//把store的dispatch映射到props中,返回的对象就是映射到props中的值
const mapDispatchToProps = (dispatch)=>{
    return {
        changeInputVal(e){
            const action = {
                type:"change_input_val",
                value:e.target.value
            }
            dispatch(action)
        }
    }
}

//让TodoList与store做连接,如何做连接呢,有个映射关系如下:把mapStateToProps和mapDispatchToProps都映射到props中
export default connect(mapStateToProps,mapDispatchToProps)(TodoList);

加入actionTypes和actionCreator,修改后代码如下

import { Component } from "react";
import { connect } from "react-redux";
import { addItem, changeInputVal,delItem } from "./store/actionCreator.js";
class TodoList extends Component {
  constructor(props) {
    super(props);
  }
  render() {
    const { changeInputVal, add, list, del } = this.props;
    return (
      <div>
        <input
          type="text"
          value={this.props.inputVal}
          onChange={changeInputVal}
        />
        <button onClick={add}>提交</button>
        <ul>
            {
                list.map((item,index)=>{
                    return <li onClick={(e)=>{del(index)}} key={index}>{item}</li>
                })
            }
        </ul>
      </div>
    );
  }
}

☆☆☆☆☆☆☆☆接着上面的内容☆☆☆☆☆☆☆

//把store中的数据映射到props中,返回的对象就是映射到props中的值
const mapStateToProps = (state) => {
  return {
    inputVal: state.inputVal,
    list: state.list,
  };
};
//把store的dispatch映射到props中,返回的对象就是映射到props中的值
const mapDispatchToProps = (dispatch) => {
  return {
    changeInputVal(e) {
      const action = changeInputVal(e.target.value);
      dispatch(action);
    },
    add() {
      const action = addItem();
      dispatch(action);
    },
    del(index){
        const action = delItem(index);
        dispatch(action);
    }
  };
};

//让TodoList与store做连接,如何做连接有个映射关系就是mapStateToProps
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);

由于TodoList中没有业务逻辑,只有一个render函数,所以可以把TodoList写成一个ui组件,改造后代码如下

import { connect } from "react-redux";
import { addItem, changeInputVal,delItem } from "./store/actionCreator.js";

const TodoList = (props)=>{
  const { changeInputVal, add, list, del,inputVal } = props;
  return (
    <div>
      <input
        type="text"
        value={inputVal}
        onChange={changeInputVal}
      />
      <button onClick={add}>提交</button>
      <ul>
          {
              list.map((item,index)=>{
                  return <li onClick={(e)=>{del(index)}} key={index}>{item}</li>
              })
          }
      </ul>
    </div>
  );
}
//中间代码省略...
/**
 * 让TodoList与store做连接,如何做连接有个映射关系就是mapStateToProps
 * 在一个组件中一般是返回组件,此处返回的是connect函数执行的结果,上面代码改造之后
 * TodoList是一个ui组件,connect函数把ui组件和业务逻辑结合,最后得到的是一个容器组件,
 * 所以导出的就是一个容器组件
*/
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
上一篇 下一篇

猜你喜欢

热点阅读