菜鸟的第一个react项目总结(react+dva)

#1

react part

1.props属性

props是一个从外部传进组件的参数,主要作为就是从父组件向子组件传递数据,它具有可读性和不变性,只能通过外部组件主动传入新的props来重新渲染子组件,否则子组件的props以及展现形式不会改变。


//父组件
class Farther extends React.Component{
    state = {
        test:'我是父组件'
    };
    render() {
        return (
            <Children test={this.state.test} />
        )
    }
}

//子组件
class Children extends React.Component {
    render() {
        //通过props获取
        const {test} = this.props
        return (
            <div>{test}</div>
        )
    }
}

2.state属性

state顾名思义就是状态,它只是用来控制这个组件本身自己的状态,我们可以用state来完成对行为的控制、数据的更新、界面的渲染.

setState更新是异步的,事件处理过程 setState 不会同步更新 this.state, React 控制之外的情况, setState 会同步更新 this.state

总结:尽量少地用 state,尽量多地用 props。原因是这样会降低代码维护的难度,也会在一定程度上增强组件的可复用性,react鼓励我们编写函数式组件。

3.生命周期

  • componentDidMount

在组件已经完全挂载到网页上才会调用被执行,保证数据的加载。用来加载外部数据用的,或处理其他的副作用代码, 在这方法中调用setState方法,会触发重渲染

注:做项目的时候发现,当父组件传参子组件时,子组件的componentDidMount通过this.props拿不到参数,原因是获取服务器参数的函数是异步调用的,在组件初始化的时候获取到的是初始值,当异步函数执行后,值发生改变,此时将参数传递给子组件,所以在组件挂载之后执行的函数,在render里可以获取得到。

  • componentDidUpdate

这个生命周期用于组件更新结束之后执行,在初始化render时不执行。
用处:当我需要父传子的时候某个参数,在进入页面的时候判断是否弹窗时,由于使用componentDidMount拿不到this.props.data,使用componentWillReceiveProps则会我一改变state时这个方法就调用一次,所以用到了componentDidUpdate

    componentDidUpdate(prevProps, prevState) {
        <!--一定要给个判断条件,不然就会死循环-->
        if (prevProps.data !== this.props.data) {
          const { data } = this.props;
          if (data) {
            this.setState({
              data
            });
          }
        }
    }

总结:我们知道,react函数每次更新组件(或者数据)都需要this.setState(state)来进行,这里补充每次调用setState()结束之后都会自动调用componentDidUpdate()钩子,因此,如果有每次更新都要进行的行动都可以写在这个钩子中。

  • render

    我们经常会看到render执行很多次,通常render渲染有以下情况:

    1. 首次加载,即数据进来首先执行render渲染基本页面组件
    2. setState改变组件内部state。(只要触发setState一次就会render一次)
    3. 接受到新的props

注:一般情况下我们会有三次render,首次加载、componentDidMount发送ajax时render、得到回应render

以上是我项目中用到的生命周期,具体生命周期可以看 https://www.cnblogs.com/qiaojie/p/6135180.html

4.事件绑定

(1) 在构造函数中使用bind绑定this

class Button extends React.Component {
   constructor(props) {
       super(props);
       this.handleClick = this.handleClick.bind(this);
     }
     handleClick(){
       console.log('this is:', this);
     }
     render() {
       return (
         <button onClick={this.handleClick}>
           Click me
         </button>
       );
     }
   }

(2) 在调用的时候使用bind绑定this

class Button extends React.Component {
  handleClick(){
    console.log('我是点击');
  }
  render() {
    return (
      <button onClick={this.handleClick.bind(this)}>
        Click me
      </button>
    );
  }
}

(3) 在调用的时候使用箭头函数绑定this

class Button extends React.Component {
  handleClick(){
    console.log('我是点击');
  }
  render() {
    return (
      <button onClick={()=>this.handleClick()}>
        Click me
      </button>
    );
  }
}

(4) 使用属性初始化器语法绑定this(实验性)

class Button extends React.Component {
  handleClick=()=>{
    console.log('我是点击');
  }
  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}

总结:方式1是官方推荐的绑定方式,也是性能最好的方式。方式2和方式3会有性能影响并且当方法作为属性传递给子组件的时候会引起重渲问题。方式4目前属于实验性语法,但是是最好的绑定方式,需要结合bable转译。我比较习惯用方法4

dva part

官网说法:dva 首先是一个基于 redux 和 redux-saga 的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-router 和 fetch,所以也可以理解为一个轻量级的应用框架。
dva由以下部分组成:

1.定义 Model
import { concernDelete } from '@/services/api';

export default {
  namespace: 'list', //命名空间, 表示在全局 state 上的 key
  state: {
    data: [],
  },
//这块是redux-saga框架的属性
  effects: {
    *remove({ payload }, { call, put }) {
       //concernDelete接口api
      const response = yield call(concernDelete, payload)
      // put函数是用来发送action的
      yield put({
        type: 'delete',
        payload: payload,
      });
    },
  },

//reducers 等同于 redux 里的 reducer,接收 action,同步更新 state
  reducers: {
    // 不符合redux理念,有空要改过来
    delete(state, { payload }) {
      const idx = state.concerns.findIndex(item => item.id == payload.id);
      state.concerns.splice(idx, 1);
      return state;
    },
  },
};

注:

effect:
相当于redux框架中的dispatch函数,当put一个action后,reducer中就会计算新的state并返回,注意: put 也是阻塞 effect。

call(fn, …args):
相当于可以调用其他函数的函数,它命令 middleware 来调用fn 函数, args为函数的参数,注意: fn 函数可以是一个 Generator 函数,也可以是一个返回 Promise 的普通函数,call 函数也是阻塞 effect。**

2.编写 UI Component
   const columns = [
      {
        title: '姓名',
        dataIndex: 'title',
        render: (...text) => <List.Item>{text[1].name}</List.Item>,
      },
      {
        title: '管理',
        dataIndex: 'manage',
        render: (...text) => {
          const editAndDelete = (key, rowKey) => {
            if (key === 'edit') this.showEditModal(rowKey);
            else if (key === 'delete') {
              Modal.confirm({
                title: '删除关心的人',
                content: '确定删除关心的人吗?',
                okText: '确认',
                cancelText: '取消',
                onOk: () => this.deleteItem(text[1].id, text[1].isMainPerson),
              });
            }
          };
          return (
            <List.Item
              actions={[
                <a
                  data-key="edit"
                  onClick={e => {
                    e.preventDefault();
                    this.showEditModal(text[1], { edit: 'edit' });
                  }}
                >
                  编辑
                </a>,
                <a
                  data-key="delete"
                  onClick={e => {
                    e.preventDefault();
                    const {
                      parentNode: {
                        parentNode: {
                          parentNode: {
                            parentNode: {
                              parentNode: {
                                dataset: { rowKey },
                              },
                            },
                          },
                        },
                      },
                    } = e.target;
                    editAndDelete(e.target.dataset.key, rowKey);
                  }}
                >
                  删除
                </a>,
              ]}
            />
          );
        },
      },
    ];

3.connect 起来
@connect(({ list, loading }) => ({
  list,
  loading: loading.models.list,
}))

class BasicList extends PureComponent {
  state = {
    selectedRows: [],
  };
  componentDidMount() {
    const { dispatch } = this.props;
    dispatch({
      type: 'list/fetch',
      payload: { isDeleted: 0 },
      //如果model层effects有传入callback传参,并将response回调的话,这里就可以拿到callbak
      // callback(res){
      //   console.log(res)
      // }
    });
  }

简书地址:https://www.jianshu.com/p/7bf60b913865
掘金地址:https://juejin.im/post/5ca47af5518825440c48c44e
未完待续…

1 Like