React 学习笔记

1. 特点

1.1. 特征

  • 支持JXS
  • 支持TypeScript

1.2. 优点

  • 函数式
  • 组件化

1.3. 缺点

  • 学习成本较高
  • 基础要求高

2. 语法

2.1. 渲染元素

<id="root"></>
<script type="text/babel">
  let element = <>Hello World</>;
  let root = $('#root').get(0);
  ReactDOM.render(element, root);
</script>

2.2. 组件声明

class Test extends React.Component {
  render() {
    return <>1</>;
  }
}
let element = <Test />;

2.3. 组件传参

class Test extends React.Component {
  render() {
    return <>{this.props.data}</>;
  }
}
let element = <Test data="test" />;

2.4. 组件嵌套

class Child extends React.Component {
  render() {
    return <>{this.props.data}</>
  }
}
class Parent extends React.Component {
  render() {
    return (
      <>
        <Child data="1" />
        <Child data="2" />
      </>
    );
  }
}

2.5. 生命周期

class Test extends React.Component {
  constructor(props) {super(props);} // 构造函数
  componentWillMount() {} // 将挂载组件
  componentDidMount() {} // 已挂载组件
  componentWillUnmount() {} // 将卸载组件

  componentWillReceiveProps (nextProps) {} // 接收数据
  getDerivedStateFromProps(nextProps, prevState) {} // 获取更新数据
  shouldComponentUpdate(nextProps, nextState) {} // 是否更新数据 
  componentWillUpdate (nextProps, nextState) {} // 将更新数据 可能不被渲染
  getSnapshotBeforeUpdate(prevProps, prevState) {} // 将更新数据 肯定被渲染
  render() {} // 渲染
  componentDidUpdate(prevProps, prevState) {} // 已更新数据
}

2.6. 绑定事件

class Test extends React.Component {
  constructor(props) {
    super(props);
    this.state = {number: 0};
    this.click = this.click.bind(this);
  }

  click() {
    this.setState({
      number: this.state.number + 1,
    });
  }

  render() {
    return <button onClick={this.click}>{this.state.number}</button>;
  }
}

2.7. 表单

class Form extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      text: '',
      number: '',
      date: '',
      time: '',
      file: '',
      password: '',
      checkbox: '',
      radio: '',
      textarea: '',
      select: '',
    };

    this.handleInputChange  = this.handleInputChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleInputChange (event) {
    const target = event.target;
    const name = target.name;
    const value = ['checkbox', 'radio'].indexOf(target.type) == -1 ? target.value : target.checked;

    this.setState({[name]: value});
  }

  handleSubmit(event) {
    console.log(this.state);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <input type="text" name="text" value={this.state.text} onChange={this.handleInputChange} />
        <input type="number" name="number" value={this.state.number} onChange={this.handleInputChange} />
        <input type="date" name="date" value={this.state.date} onChange={this.handleInputChange} />
        <input type="time" name="time" value={this.state.time} onChange={this.handleInputChange} />
        <input type="file" name="file" value={this.state.file} onChange={this.handleInputChange} />
        <input type="password" name="password" value={this.state.password} onChange={this.handleInputChange} />
        <input type="checkbox" name="checkbox" checked={this.state.checkbox} onChange={this.handleInputChange} />
        <input type="radio" name="radio" checked={this.state.radio} onChange={this.handleInputChange} />
        <textarea name="textarea" value={this.state.textarea} onChange={this.handleInputChange} />
        <select name="select" value={this.state.select} onChange={this.handleInputChange}>{[1, 2].map((v, k) => <option key={k} value={k}>{v}</option>)}</select>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

2.8. 调用父组件

class A extends React.Component {
  render() {
    return <button onClick={() => this.props.case(this.props.data)}>{this.props.data}</button>;
  }
}

class B extends React.Component {
  constructor(props) {
    super(props);
    this.show = (e) => alert(e);
  }

  render() {
    return (
      <>
        <A data="1" case={this.show} />
        <A data="2" case={this.show} />
      </>
    );
  }
}

2.9. 继承

class A extends React.Component {
  render() {
    return <>{this.props.children}</>;
  }
}

class B extends React.Component {
  render() {
    return (
      <A>
        <>{this.props.one}</>
        {this.props.two}
        {this.props.children}
      </A>
    );
  }
}

class C extends React.Component {
  constructor(props) {
    super(props);
    this.state = {text: '2'};
  }

  render() {
    return (
      <B one="1" two={<input value={this.state.text} onChange={(e) => this.setState({text: e.target.value})} />}>
        <button onClick={() => alert(`${this.state.text}`)}>3</button>
      </B>
    );
  }
}

3. JSX

3.1. 运算

let element = <>{1 + 2}</>;

3.2. 判断

let element = <>{true ? 1 : 0}</>;

3.3. 样式表

let style = {
  color: '#00f',
};
let element = <style={style}>Hello</>;

3.4. 数组

let arr = [
  <>1</>,
  <>2</>,
];
let element = <>{arr}</>;

3.5. 判断

let element = (
  <>
    {true && <>1</>}
    {false ? <>2</> : <>3</>}
  </>
);

3.6. 循环

const arr = [1, 2, 3];
const lis = arr.map((v, k) => <key={k}>{v}</>);
let element = <>{lis}</>;

4. React Hooks

4.1. 普通变量

import { useState } from 'react';
const [test, setTest] = useState({});

4.2. 状态变量

import { useReducer } from 'react';
const init = {test: 0};
function reducer(state, action) {
  switch(action.type) {
    case: 'test': return {...state, test: 1};
	default: throw new Error();
  }
}
function Test() {
  const [state, dispatch = useReducer(reducer, init);
  return <onClick={() => dispatch({type: 'test'})></>;
}

4.3. 事件

import { useEffect } from 'react';
import { useLayoutEffect } from 'react';
import { useCallback } from 'react';
import { useMemo } from 'react';
useEffect(() => {}); // 异步事件
useEffect(() => {}, []); // 调用限制
useEffect(() => ({})); // 卸载清除
useLayoutEffect(() => {}); // 渲染前执行
const callback = useCallback(() => {}); // 限制回调
const memo = useMemo(() => {}); // 限制处理

4.4. 上下文

import { createContext } from 'react';
import { useContext } from 'react';
const TestContext = createContext(0);
function Parent() {
  return <TestContext.Provider value={1}><Child /></TestContext.Provider>;
}
function Child() {
  const test = useContext(TestContext);
  return <>{test}</>;
}

4.5. Ref对象

import { useRef } from 'react';
const ref = useRef(null);
let element = <input type="text" ref={ref} />;

4.6. Ref函数

import { useRef } from 'react';
import { useImperativeHandle } from 'reac';
import { forwardRef } from 'react';
const Child = forwardRef((props, ref) => {
  const r = useRef();
  useImperativeHandle(ref, () => ({
    f: () => {
      r.current.focus();
    },
  }));
  return <input type="text" ref={r}>;
});
function Parent() {
  const r = useRef();
  return <><onClick={() => r.current.f()}>Click</><Parent ref={r}></>
}

5. React Router

5.1. 关联URL

import { BrowserRouter } from 'react-router-dom"
let element = <BrowserRouter></></BrowserRouter>;

5.2. 添加链接

import { Link } from 'react-router-dom';
let element = <Link to="/">Index</Link>;

5.3. 链接状态

import { NavLink } from 'react-router-dom';
let element = <NavLink>{isActive}</NavLink>;

5.4. 添加路由

import { Routes } from 'react-router-dom';
import { Route } from 'react-router-dom';
let element = <BrowserRouter><Routes><Route path="/" element={</>} /></Routes></BrowserRouter>;

5.5. 路由嵌套

import { Outlet } from 'react-router-dom';
let element = <Route path="/" element={</>}><Route path="test" element={</>} /></Route><Outlet />;

5.6. 路由循环

let element = {[1, 2, 3].map((v, k) => (<Link to={`/${v}`} key={k}>{v}</Link>))};

5.7. 路由通配符

let element = <Route path="*" element={</} />;

5.8. 路由参数

let element = <Route path=":id" element={<Test />} />;

import { useParams } from 'react-router-dom';
export default function Test() {
  return <>{useParams().id}</>;
}

5.9. 路由搜索

import { useSearchParams } from 'react-router-dom';
let [searchParams, setSearchParams] = useSearchParams();

5.10. 路由刷新

import { useNavigate } from 'react-router-dom';
let navigate = useNavigate();
let element = <onClick={() => navigate('/test')} />;

6. React Que

6.1. 开发工具

import { ReactQueryDevtools } from 'react-query/devtools';
let element = <ReactQueryDevtools />;

6.2. 查询数据

import { useQuery } from 'react-query';
import { QueryClient } from 'react-query';
import { QueryClientProvider } from 'react-query';
const queryClient = new QueryClient();
function Parent() {
  return (
    <QueryClientProvider client={queryClient}>
      <Child />
    </QueryClientProvider>
  );
}
function Child() {
  const { isLoading, isError, data, error } = useQuery('key', () => 0);
  if(isLoading) {
    return <>Loading</>
  } else if (isError) {
    return <>{error.message}</>
  } else {
    return <>{data}</>
  }
}

6.3. 改变数据

import { useMutation } from 'react-query';
const mutation = useMutation((data) => axios.post('/api', data));
mutation.mutate({});

6.4. 常用参数

useQuery(['key', 1, {test: true}], () => 0); // 数组键值
useQuery(['key', {a, b}], ({ params }) => {const [_key, { a, b }] = params}); // 函数传参
useQuery({queryKey: ['key', 1], queryFn: () => 0}); // 对象参数
useQuery('key', () => 0, {enabled: true}); // 是否启用
useQuery('key', () => 0, {retry: 10}); // 重试十次
useQuery('key', () => 0, {retry: false}); // 禁止重试
useQuery('key', () => 0, {retry: true}); // 无限重试
useQuery('key', () => 0, {retry:(count,error)=> true}); // 自定义重试
useQuery('key', () => 0, {keepPreviousData: true}); // 保留前次数据
useQuery('key', () => 0, {initialData: []}); // 初始化数据
useQuery('key', () => 0, {onSuccess: () => {}}); // 执行成功
useQuery('key', () => 0, {onError: () => {}}); // 执行失败
useQuery('key', () => 0, {onSettled: () => {}}); // 执行结束

6.5. 批量查询

import { useQueries } from 'react-query';
const tests = useQueries(
  [{id:1},{id:2},{id:3}].forEach((val) => {
    return {
      queryKey: ['test', val.id],
      queryFn: () => fetchUserById(val.id),
    };
  }),
);

6.6. 失效查询

import { useQueryClient } from 'react-query';
const queryClient = useQueryClient();
queryClient.invalidateQueries('test');

6.7. 直接更新

import { useQueryClient } from 'react-query';
const queryClient = useQueryClient();
queryClient.setQueryData([test], 1);

7. Redux

7.1. Action

let action = () => {
  return {
    type: '',
  };
}

7.2. Reducer

let reducer = (state = {}, action) => {
  switch (action.type) {
    case '':
      return {
        ...state,
      };
    default:
      return state;
  }
}

7.3. Store

import { createStore } from 'redux';
let store = createStore(reducer); // 创建
let test = store.getState(); // 获取数据
store.dispatch(action); // 发出行为(更新数据)
const unsubscribe = store.subscribe(() => {}); // 监听行为
unsubscribe(); // 停止监听

7.4. React Redux

import { Provider } from 'react-redux';
import { connect } from 'react-redux';
let Receiver = connect(state => state, null)((props) => <></>); // 获取数据
let Sender = export default connect(null, (dispatch) => { // 发出行为(更新数据)
  return {send: () => dispatch({type: 'add_action'})}
})((props) => <button onClick={() => props.send()}>+</button>);
let App = (
  <Provider store={store}>
    <Sender />
    <Receiver />
  </Provider>
);

7.5. API

import { combineReducers } from 'react-redux';
let reducers = combineReducers({reducer, reducer});

import { bindActionCreators } from 'react-redux';
let dispatch = bindActionCreators({reducer, reducer}, dispatch);

import { applyMiddleware } from 'react-redux';
import { compose } from 'react-redux';
let store = createStore(reducer, [preloadedState], enhancer);
let enhancer = applyMiddleware(m1, m2);
let func = compose(m1, m2);

import { connect } from 'react-redux';
let component = connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]);
let mapStateToProps = (state) => ({});
let mapDispatchToProps = (dispatch, ownProps) => ({test: () => dispatch({type: ''})});
let mergeProps = (stateProps, dispatchProps, ownProps) => ({});

import { useStore } from 'react-redux';
import { useSelector } from 'react-redux';
import { useDispatch } from 'react-redux';
let store = useStore();
let value = useSelector(state => state.value);
let dispatch = useDispatch();

7.6. Redux Middleware

import thunk from 'redux-thunk';
import promise from 'redux-promise';
import logger from 'redux-logger';
const store = createStore(reducers, applyMiddleware(thunk, promise, logger));

参考

版权协议

知识共享许可协议

本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 版本许可协议进行许可。