zoukankan      html  css  js  c++  java
  • react系列

    3.react-router 和react-router-dom的区别  https://blog.csdn.net/sinat_17775997/article/details/69218382

    4.Route关联component有多种形式(render、component、children) children定义形式与render和component的不同在于,children的执行与match无关,即使match为null,children函数也是会执行的
    (1) component 会重复加载,每次重新调用React.createElement(component, props)
    (2) render 内联渲染,不会重新加载
    5.插入html元素

     6.redux-thunk

    redux-thunk实现了相关异步流程内聚到redux的流程中,实现middleware的功能,也便于项目的开发与维护,避免冗余代码。而实现的方式便是改写redux中的dispatch API,使其可以除PlainObject外,接受一个函数作为参数。

    //action.js
    const custom = (data) => {
      type: 'SET_CUSTOM_DATA',
      data: data    
    }
    
    dispatch(custom({}))
    
    //redux-thunk
    
    const custom = (data) => {
      return async (dispatch, getState) => {
         //异步操作
         dispatch({
            type: 'SET_CUSTOM_DATA',
            data: data 
        })
      }
        
    }
    dispatch(custom({}))

    7. react-redux中<Provider>组件的作用,以及如何实现异步加载reducer

    import { Provider } from 'react-redux'
    import { createStore } from 'redux'
    import todoApp from './reducers'
    import App from './components/App'
    
    let store = createStore(todoApp);
    
    render(
      <Provider store={store}>
        <App />
      </Provider>,
      document.getElementById('root')
    )
    //App的所有子组件就默认都可以拿到state
    //它的原理是React组件的context属性
    
    class Provider extends Component {
      //store放在了上下文对象context上面。然后,子组件就可以从context拿到store
      getChildContext() {
        return {
          store: this.props.store
        };
      }
      render() {
        return this.props.children;
      }
    }
    
    Provider.childContextTypes = {
      store: React.PropTypes.object
    }        
    
    
    //子组件调用
    class VisibleTodoList extends Component {
      componentDidMount() {
        const { store } = this.context;
        this.unsubscribe = store.subscribe(() =>
          this.forceUpdate()
        );
      }
    
      render() {
        const props = this.props;
        const { store } = this.context;
        const state = store.getState();
        // ...
      }
    }
    
    VisibleTodoList.contextTypes = {
      store: React.PropTypes.object
    }

    //react组件的context属性应用,将store嵌入,通过this.context.store获取
    //injectReducer在项目中异步加载reducers,具体的reducer可以在生命周期函数中加载进去

     8.  react-redux

    export default connect(function (state, props){
      /*return {
        ...state,
        name: [state.name, props.name]
      };*/
      // state, props如果同名,可以通过这个函数决定是获取哪个
      return state.user;
    }, {
      setName(name){
        return {
          type: SET_NAME,
          name
        };
      },
      addAge(n){
        return {
          type: ADD_AGE,
          n
        }
      }
    })(App);

     9. 高阶组件

    //withHoc.js
    import React, { Component } from 'react';
    
    export default (params) => (WrappedComponent) => {
        return class From extends Component {
            //方便使用react-devtool调试时显示不同组件名
            static displayName = `From(${WrappedComponent.name || WrappedComponent.displayName})`
            render() {
              return (
                <div className="withHoc">
                  <div>{params}</div>
                  <WrappedComponent {...this.props} {...this.state}></WrappedComponent>
                </div>
              );
            }
          }
    }
    
    //a.js
    import React, { Component } from 'react';
    import withHoc from './withHoc.js';
    
    class A extends Component {
      render() {
        return (
          <div className="A">
            <div>A component</div>
          </div>
        );
      }
    }
    
    export default withHoc('a')(A);

     10. withRouter

    目的就是让被修饰的组件可以从属性中获取history,location,match,
    路由组件可以直接获取这些属性,而非路由组件就必须通过withRouter修饰后才能获取这些属性了,
    比如 <Route path='/' component={App}/>

    App组件就可以直接获取路由中这些属性了,但是,如果App组件中如果有一个子组件Foo,那么Foo就不能直接获取路由中的属性了,必须通过withRouter修饰后才能获取到。

    //用于js实现路由跳转
    this.props.history.push('/chat)

     11. Redux DevTools 扩展的使用说明

    if (process.env.NODE_ENV === 'development') {
      const devToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION__
    
      if (typeof devToolsExtension === 'function') {
        enhancers.push(devToolsExtension())
      }
    }
    
    const composedEnhancers = compose(
      applyMiddleware(...middlewares),
      ...enhancers
    )
    
    //或者
    const enhancers = []
    let composeEnhancers = compose
    
    // 在development模式,使用redux-devtools-extension
    if (process.env.NODE_ENV === 'development') {
      if (typeof window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ === 'function') {
        composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
      }
    }
    const store = createReduxStore(
      makeRootReducer(),
      initialState,
      composeEnhancers(
        applyMiddleware(...middleware),
        ...enhancers
      )
    )

    12. 常用npm包

    connected-react-router
    core-js 
    reselect // computed
    redux-undo // 撤销,重做
    react-loadable //懒加载

    13. px2rem

    // config-overrides.js
    const px2rem=require('postcss-px2rem-exclude')
    
    module.exports = {
      webpack: override(
    
        // 用js的方式导入antd及其样式:style为true表示导入antd.less; 为false表示不使用js的方式导入antd.less或antd.css;为'css'表示使用antd.css;
        fixBabelImports("import", {
          libraryName: "antd-mobile", libraryDirectory: "es", style: true  // 为false或css会导致addLessLoader失效
        }),
        addLessLoader({
          javascriptEnabled: true,
          // modifyVars: { "@primary-color": "#D24545" } // 深红色
        }),
        addPostcssPlugins([
          px2rem({
            remUnit: 75,
    
            // 仅排除对antd-mobile的px2rem转化
            exclude: /node_modules/antd-mobile/i
          })
        ]),
        disableEsLint() // 取消eslint检查,加快yarn start速度
      ),
      devServer: overrideDevServer(
        // dev server plugin
        watchAll()
      )
    }
    // 某一项不想转为rem
    border: 1px solid #ccc; /*no*/

    vue-cli3用的是postcss-plugin-px2rem; 实现原理一样。重要!! 如果个别地方不想转化px。可以简单的使用大写的 PX 或 Px

    14. withRouter导致组件重复渲染

    React Router 4 把Route当作普通的React组件,可以在任意组件内使用Route;

    withRouter 为非路由组件提供了location,history,match三个参数;但是有时会发现有些接口会重复调用,这个是由于组件重新渲染的原因

    经过Redux connect后的Home组件,在更新阶段,会使用浅比较,但是由于Route组件导致这个失效

    componentWillReceiveProps(nextProps, nextContext) {
        warning(
          !(nextProps.location && !this.props.location),
          '<Route> elements should not change from uncontrolled to controlled (or vice versa). You initially used no "location" prop and then provided one on a subsequent render.'
        )
    
        warning(
          !(!nextProps.location && this.props.location),
          '<Route> elements should not change from controlled to uncontrolled (or vice versa). You provided a "location" prop initially but omitted it on a subsequent render.'
        )
    
        // 注意这里,computeMatch每次返回的都是一个新对象,如此一来,每次Route更新,setState都会重新设置一个新的match对象
        this.setState({
          match: this.computeMatch(nextProps, nextContext.router)
        })
      }
    
      render() {
        const { match } = this.state
        const { children, component, render } = this.props
        const { history, route, staticContext } = this.context.router
        const location = this.props.location || route.location
        // 注意这里,这是传递给Route中的组件的属性
        const props = { match, location, history, staticContext }
    
        if (component)
          return match ? React.createElement(component, props) : null
    
        if (render)
          return match ? render(props) : null
    
        if (typeof children === 'function')
          return children(props)
    
        if (children && !isEmptyChildren(children))
          return React.Children.only(children)
    
        return null
      }

    这样,每次Route更新(componentWillReceiveProps被调用),都将创建一个新的match;

    导致Redux的浅比较失败,进而触发组件的重新渲染

    解决方法:1⃣️. connected-react-router 2⃣️. 直接引用history.js文件

    15.input 在IE11,不触发onchange

    <input
      type='text'
      value={this.state.value}
      onCompositionStart={this.handleComposition}
      onCompositionUpdate={this.handleComposition}
      onCompositionEnd={this.handleComposition}
      onChange={this.handleChange}
    />
    
    //前2个事件都在onChange之前触发,onCompositionEnd是在onChange之后触发。
    //如果直接输入完成是不会触发这三个事件的,只有onChange事件。比如直接输入英文
    
    // ie11下中文输入法会不触发onChange,所以也需要setState,否则此时会发现中文输入进去后输入框没有变换
    
    /**
       * 中文输入法,选词
       */
      handleComposition = (e) => {
        this.isOnComposition = e.type !== 'compositionend'
        if (!this.isOnComposition) {
          //ie11不触发onchange导致中文不展示
          this.setState({
            value: e.target.value
          })
          this.handleInputAndSearch(e.target.value)
        }

     16. 如果map的组件为受控组件,则使用索引并不会产生问题,但是如果为非受控组件,例如input等,则会由于复用标签元素导致value并未更改

    17. setState机制https://github.com/sisterAn/blog/issues/26

    批处理的原因,举例来说,如果我们在浏览器中click处理,都ChildParent调用setState,我们不想重新渲染Child两次

    补充,这里输出 0,0,3,4

    componentDidMount() {
          this.setState((prevState, props) => ({
            val: prevState.val + 1
          }))
          console.log(this.state.val)
          this.setState((prevState, props) => ({
            val: prevState.val + 1
          }))
          console.log(this.state.val)
      
          setTimeout(() => {
            this.setState({val: this.state.val + 1});
            console.log(this.state.val);  // 第 3 次 log
      
            this.setState({val: this.state.val + 1});
            console.log(this.state.val);  // 第 4 次 log
          }, 0);
    
        }
    // 0,1 "logbefore", 2 "log",3,4
    componentDidMount() {
          this.setState((prevState, props) => ({
            val: prevState.val + 1
          }))
          console.log(this.state.val)
          Promise.resolve().then(() => {
            console.log(this.state.val, 'logbefore');
            this.setState({val: this.state.val + 1});
            console.log(this.state.val, 'log');
          })
      
          setTimeout(() => {
            this.setState({val: this.state.val + 1});
            console.log(this.state.val);  // 第 3 次 log
      
            this.setState({val: this.state.val + 1});
            console.log(this.state.val);  // 第 4 次 log
          }, 0);
    
        }

    (图片链接来源:https://stackoverflow.com/questions/48563650/does-react-keep-the-order-for-state-updates/48610973#48610973

     源码路径(v16.9.0)

    /react/packages/react-test-renderer/src/ReactShallowRenderer.js

    class Updater {
      constructor(renderer) {
        this._renderer = renderer;
        this._callbacks = [];
      }
      //...
      enqueueSetState(publicInstance, partialState, callback, callerName) {
        this._enqueueCallback(callback, publicInstance);
        const currentState = this._renderer._newState || publicInstance.state;
    
        if (typeof partialState === 'function') {
          partialState = partialState.call(
            publicInstance,
            currentState, //这里确保每次的state都是当时最新的
            publicInstance.props,
          );
        }
    
        // Null and undefined are treated as no-ops.
        if (partialState === null || partialState === undefined) {
          return;
        }
    
        this._renderer._newState = {
          ...currentState,
          ...partialState,
        };
    
        this._renderer.render(this._renderer._element, this._renderer._context);
      }
    }

     /react/src/renderers/shared/stack/reconciler/ReactUpdates.js

    function enqueueUpdate(component) {
      ensureInjected();
    
      // Various parts of our code (such as ReactCompositeComponent's
      // _renderValidatedComponent) assume that calls to render aren't nested;
      // verify that that's the case. (This is called by each top-level update
      // function, like setState, forceUpdate, etc.; creation and
      // destruction of top-level components is guarded in ReactMount.)
    
      if (!batchingStrategy.isBatchingUpdates) {// 还是根据isBatchingUpdates
        batchingStrategy.batchedUpdates(enqueueUpdate, component);
        return;
      }
    
      dirtyComponents.push(component);
      if (component._updateBatchNumber == null) {
        component._updateBatchNumber = updateBatchNumber + 1;
      }
    }

    https://juejin.im/post/5c5c33aef265da2d8d69b639#heading-3

  • 相关阅读:
    mysql升级大致
    初始化配置文件的使用:/etc/my.cnf
    mysql用户管理
    MySql的逻辑结构(抽象结构)与物理结构
    5.7与5.6版本在部署方面的改变
    MySql服务器进程结构
    MySql服务器构成 --实列
    mysql客户端与服务器端模型
    RDBMS和NoSQL区别即主流sql
    MySql基本操作
  • 原文地址:https://www.cnblogs.com/luguiqing/p/10211981.html
Copyright © 2011-2022 走看看