React学习大全

一、React

1.jsx:执行时会调用React.createElement()

const name = 'Josh Perez';
const element = 

Hello, {name}

; ReactDOM.render( element, document.getElementById('root') );

2. 列表渲染:map方法,key一般为id,实在没有就使用`index-${index}`,需为字符串

    {numbers.map((number) => )}

3.组件:分为函数组件和class组件

// 函数组件
function btn(props) {
    return 
}
// class组件
class btn extends React.Component{
    render() {
        return 
    }
}

4.state和props:单向数据流,从父到子

setState可能会是异步的,解决方法可以让 setState() 接收一个函数而不是一个对象

this.setState((state, props) => ({
  counter: state.counter + props.increment
}));

5.生命周期:

render:为纯函数,如果shouldComponentUpdate() 返回 false则不会调用render

constructor:构造函数,直接给state赋值,在外部的话用this.setState()

constructor(props) {
  super(props);
  // 不要在这里调用 this.setState()
  this.state = { counter: 0 };
  this.handleClick = this.handleClick.bind(this);
}

componentDidMount:会在组件挂载后(插入 DOM 树中)立即调用,常用与api请求 

componentDidUpdate:会在更新后会被立即调用,可以进行dom操作,如果比较更新前后的prop在这也可以进行api请求或者setState,但是切记要if进行比较,如果 shouldComponentUpdate() 返回 false,则不会调用 componentDidUpdate()

componentDidUpdate(prevProps,prevState) {
  // 典型用法(不要忘记比较 props):
  if (this.props.userID !== prevProps.userID) {
    this.fetchData(this.props.userID);
  }
}

shouldComponentUpdate:

shouldComponentUpdate(nextProps, nextState) {

    //可以在此比较控制返回true会继续渲染,返回false则不会渲染,会跳过render和conponentDidUpdate
   // 在此处只应该进行浅层比较
}

 componentWillUnmount:在组件销毁前调用,可以在这里清除定时器、取消订阅 

setState:延迟批量更新,用callback使用最新的state或者在promise里使用

setState(updater, [callback])回调函数中的state是更新后的,可以直接使用

6.事件

命名:小驼峰式,例如onClick

阻止默认行为:不是return false,而是e.preventDefault

绑定this:

// 在构造函数中绑定
this.handleClick = this.handleClick.bind(this);

// public class fields 语法,建议使用
 handleClick = () => {
    console.log('this is:', this);
  }


// 箭头函数,调用时和上面两种不同
handleClick() {
    console.log('this is:', this);
}

参数传递:


7.条件渲染:if、&&、?:(三目运算符)

8.表单

受控组件:可以控制value,大部分都是并且建议使用

非受控组件:例如文件input标签,一般用ref获取值和控制dom

9.‘插槽’,可以将任何东西作为props传递下去

function FancyBorder(props) {
  return (
    
{props.children}
); }

10.父子组件和爷孙组件传值

11.refs转发:普通的ref在HOC中不会透传,需要使用React.forwardRef API

const FancyButton = React.forwardRef((props, ref) => (
    
));

// 你可以直接获取 DOM button 的 ref:
const ref = React.createRef();
Click me!;

12.高阶组件:是参数为组件,返回值为新组件的函数 

不要再render里面使用HOC

13.JSX

用户定义的组件必须以大写开头

// 当props.messages为空数组时,length为0仍然会渲染后面的 {props.messages.length && }

可以该成props.message.length>0 &&.... 

14.prop-types库:检查prop的类型

import PropTypes from 'prop-types';

class Greeting extends React.Component {
  render() {
    return (
      

Hello, {this.props.name}

); } } Greeting.propTypes = { name: PropTypes.string, // 类型 children: PropTypes.element.isRequired // 必须传 }; // 指定 props 的默认值: Greeting.defaultProps = { name: 'Stranger' };

15.API

 React.Component:创建类组件

React.PureComponent:比其多了一个shouldcomponentupdate,可以实现对prop和state的浅层对比,如果对象中包含复杂的数据结构,则可能会出错,并且这个钩子会跳过所有子组件的prop更新

React.memo:类似于前者,也只会做浅层对比,但是只适用于函数组件,仅检查props变更,若不变则React 将跳过渲染组件的操作并直接复用最近一次渲染的结果,如果函数组件中包含有useState或useContent,当 context 发生变化时,它仍会重新渲染,该函数可以接受第二个参数,为前后prop对比函数,返回的结果同shouldcomponentupdate相反,prop相同时返回true

React.createElement:参数类型可以是标签、react组件、 React fragment 类型,jsx是使用了这个函数的语法糖

React.createElement(
  type,
  [props],
  [...children]
)

React.Fragment:不额外创建dom,却可以返回多个元素,简写<>

render() {
  return (
    
      Some text.
      

A heading

); }

React.createRef:创建一个能够通过 ref 属性附加到 React 元素 

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.inputRef = React.createRef();  
  }
  componentDidMount() {
    this.inputRef.current.focus(); 
  }
  render() {
    return ; 
  }
}

 React.forwardRef:会创建一个React组件,组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中接受渲染函数作为参数。React 将使用 props 和 ref 作为参数来调用此函数。此函数应返回 React 节点。

const FancyButton = React.forwardRef((props, ref) => (  
    
));

// You can now get a ref directly to the DOM button:
const ref = React.createRef();
Click me!;

React.lazy:可以定义一个动态加载的组件,

const SomeComponent = React.lazy(() => import('./SomeComponent'));

 16.DOM:小驼峰写法

类是className,style 在 React 应用中多用于在渲染过程中添加动态计算的样式,style接受一个采用小驼峰命名属性的 JavaScript 对象

const divStyle = {
  color: 'blue',
  backgroundImage: 'url(' + imgUrl + ')',
};

function HelloWorldComponent() {
  return 
Hello World!
; }

17.HOOK(重点)

①useState:const [count, setCount] = useState(0);之后在函数组件里直接使用,类似于class组件的state,count为变量名,而setCount为更新变量的函数,不像 class 中的 this.setState,更新 state 变量总是替换它而不是合并它

setCount(prevCount => prevCount - 1)} // 传入一个箭头函数可以使用之前最新的数据

如果初始化的值需要复杂计算,则可以放入一个箭头函数,return一个值,这个初始化也是只有初始渲染时调用一次 

②useEffect:componentDidMountcomponentDidUpdate 和 componentWillUnmount 这三个函数的组合,依次以声明顺序调用,在重新渲染前会清除上一个effect,将在每轮渲染结束后执行

不需要清除的:

useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

需要清除的:会在组件卸载的时候清除

useEffect(() => {    
    ........
    return () => { // 清除
        ......
    }
});

 需要跳过effect的:传入一个依赖数组,类似于在 componentDidUpdate 中添加对 prevProps 或 prevState 的比较逻辑

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新

注:请确保数组中包含了所有外部作用域中会随时间变化并且在 effect 中使用的变量,否则你的代码会引用到先前渲染中的旧变量 导致无限循环,如果只想运行一次可以传入一个空数组

使用规则:只在最顶层使用,不要再循环、条件、嵌套函数中使用,如果要使用条件语句就把if放入effect中使用,只在react函数组件使用

③useContext:相当于 class 组件中的 static contextType = MyContext,useContext()中的参数只能是context对象本身,并且需要上级组件提供context,这里只作为消费
 

const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222"
  }
};

const ThemeContext = React.createContext(themes.light);

function App() {
  return (
    
      
    
  );
}

function Toolbar(props) {
  return (
    
); } function ThemedButton() { const theme = useContext(ThemeContext); return ( ); }

④useReducer:const [state, dispatch] = useReducer(reducer, initialArg, init);接收(state, action) => newState 的 reducer

const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      
      
    
  );
}

这里的dispatch可以从useEffect中省略,因为其实 稳定不会改变的

初始化:简单的指定初始化

 const [state, dispatch] = useReducer(
    reducer,
    {count: initialCount}  );

⑤useCallback:返回一个 memoized 回调函数,useCallback(fn, deps) 相当于 useMemo(() => fn, deps) 

const memoizedCallback = useCallback( // 依赖项数组不会作为参数传给回调函数
  () => {
    doSomething(a, b);
  },
  [a, b],
);

⑥useMemo: 返回一个 memoized 值

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

⑦useRef :useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数,常用于命令式访问组件,在一个生命周期内不会改变

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // `current` 指向已挂载到 DOM 上的文本输入元素
    inputEl.current.focus();
  };
  return (
    <>
      
      
    
  );
}

useLayoutEffect:useEffect相同,但会在所有DOM变更后同步调用 effect,可以用它来读取 DOM 布局并同步触发重渲染 

⑨useDispatch(产生dispatch)、useSelector (获取redux里面的一些值)

自定义hook:一般以use开头,本质也是函数

二、Redux

1.原则:单一数据源,只有一个store;state只可读,只能通过action来改变;使用纯函数的reducer来执行修改

2.action:一般类型为{type: 'xxxx, aaa:'xxxxxxxx'},其中type一般为大写常量,aaa为携带的数据

  action创建函数:返回一个action

import { Dispatch } from 'redux';
import { DriverSpreadActionType } from '../reducers/driverSpread';
import { serviceStatusList, queryCity, distributeMaps } from '../api';

export function requestServiceStatusList() {
  return async (dispath: Dispatch) => {
    const res: any = await serviceStatusList();
    if (res && res.re) {
      dispath({
        type: DriverSpreadActionType.GET_SERVICESTATUS_LIST_DATA,
        payload: {
          serviceStatusList: res.re.statusList,
        },
      });
    }
  };
}

3. reducer:接收一个旧的state和action,返回一个新的state,不要再里面进行api等操作,保持纯净

export default function (state: any = initState, action: any) {
// 一般在函数参数中直接用es6传入初始state
  switch (action.type) {
    case ActionType.SEARCH_CAR_REPORT_LIST_DATA:
      if (action.payload) {
        return Object.assign({}, state, action.payload);// 此处也可以用...对象展开运算符
      }
    ......
}

合并多个reducer:

import { combineReducers } from 'redux'

const todoApp = combineReducers({
  visibilityFilter,
  todos
})

 创建store:

import { createStore } from 'redux'
import todoApp from './reducers' // 此处的为合并之后的reducer
let store = createStore(todoApp)

 react-redux:一般用于class组件 ,用容器组件将redux变成组件的props之后传入展示组件,容器组件还能分发action

import { connect } from 'react-redux';
import { addTabPage, loadEnum } from '../../../../actions/home';

// 调用时就当成props使用
const {
      pageNo,
      pageSize,
      orderListRe,
      showOperationRecordFlag,
      enums,
      orderOptRecordRe,
    } = this.props;

const mapStateToProps = (state: any) => {
  const orderListState = state.orderList;
  const orderListHomeState = state.home;
  return {
    ...orderListState,
    ...orderListHomeState,
  };
};

export default connect(
  mapStateToProps,
  {
    addTabPage,
    loadEnum,
  }
)(OrderList);

将store传入react:

import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import todoApp from './reducers'
import App from './components/App'

let store = createStore(todoApp)

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

异步action:在action中发起api请求 

// 获取服务状态,现在一般这么使用,直接一个函数里面包括action,导出这个函数
export function requestServiceStatusList() {
  return async (dispath: Dispatch) => {
    const res: any = await serviceStatusList();
    if (res && res.re) {
      dispath({
        type: DriverSpreadActionType.GET_SERVICESTATUS_LIST_DATA,
        payload: {
          serviceStatusList: res.re.statusList,
        },
      });
    }
  };
}

 控制台log每一步的store并且可以使用异步action,thunk可以将action变成返回函数的函数

import { createStore, combineReducers, applyMiddleware } from 'redux'

let todoApp = combineReducers(reducers)
let store = createStore(
  todoApp,
  // applyMiddleware() 告诉 createStore() 如何处理中间件
  applyMiddleware(logger, crashReporter)
)


之前项目中
import reduxThunk from 'redux-thunk';

const middlewares = [reduxThunk];
if (process.env.NODE_ENV === 'development') {
    const { logger } = require('redux-logger'); // eslint-disable-line
    middlewares.push(logger);
  }
store = createStore(
    reducer(),
    initState,
    composeEnhancers(applyMiddleware(...middlewares))
  );

三、React-Router

const routes = [
  {
    exact: true, // 是否是默认
    path: '/',
    component: () => ,
  },
  {
    path: '/home',
    component: Home,
  },
  {
    path: '/login',
    component: Login,
  },

  {
    path: '/404',
    component: Login,
  },

  {
    path: '/*',
    component: () => ,
  },
];
// 顶层
return (
    
      
        
          
            {routes.map((route: any, index: number) => (
              
            ))}
          
        
      
    
  );

 

你可能感兴趣的:(前端,reactjs)