1.React.createElement:根据指定的第一个参数创建一个React元素
第一个参数是必填,传入的是似HTML标签名称,eg: ul, li
第二个参数是选填,表示的是属性,eg: className
第三个参数是选填, 子节点,eg: 要显示的文本内容
class App extends React.Component{
render(){
return (
<div className='head' id='header'>
<p className='cotent'>hello react</p>
</div>
)
}
}
React.createElement可以写成如下:
class App extends React.Component{
render(){
return(
React.createElement(
'div',
{
className:'head',
id:'header'
},
React.createElement(
'p',
{
className:'cotent',
},
'hello react'
)
)
)
}
}
2.第三方包classnames
作用:可以根据对象的方式来确定样式名
前提:npm install classnames
import classNames from 'classnames';
class App extends React.Component{
render(){
let {color} = this.props
return (
<div className='head' id='header'>
<p className={classNames('yellow',{'blue':color=='blue'},{'red':color=='red'})}>根据传参确定样式</p>
</div>
)
}
}
3.React自带Fragment组件
作用:因为React语法在渲染return方法中必须有一个根标签,而有的时候根标签毫无作用,这个时候我们就可以使用Fragment组件,Fragment不会产生在DOM中产生新的标签
import React, { Component,Fragment } from 'react'
class App extends Component {
render() {
return (
<Fragment>
<Header />
<Input />
</Fragment>
)
}
}
4.向Header组件中传递Input组件的两种方式
第一种:children方式传递
import {Header, Input} from './components/index';
<Header>
<Input />
</Header>
在Header组件中
render() {
let {children} = this.props;
return (
<div>
{
children
}
</div>
)
}
第二种:纯props方式
import {Header, Input} from './components/index';
<Header Input={<Input />}></Header>
在Header组件中
render() {
let {Input} = this.props;
return (
<div>
{ Input }
</div>
)
}
5.React组件传值检测类型
前提:npm install prop-types
import React, { Component } from 'react'
import PropTypes from 'prop-types';
(1)类组件
export default class Header extends Component {
// isRequired 表示必须的,如果父组件未传值就会报错
static propTypes = {
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
}
//如果没有传值,可以给一个默认值
static defaultProps = {
x: 0,
y: 0
}
render() {
let {x,y} = this.props;
return (
<div>
{x+y}
</div>
)
}
}
(2)函数组件
export default function Header(){
return (
<div></div>
)
}
Header.propTypes = {
x: PropTypes.number.isRequired
}
注意:可以检验的类型
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol
作者:_123hhh
链接:https://www.jianshu.com/p/a73fb26c88b5
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
6.dangerouslySetInnerHTML
作用:如果需要渲染的字符串中包括HTML标签就可以使用dangerouslySetInnerHTML
state={
title:'<div><div>标题</div><div>内容</div></div>',
}
<div dangerouslySetInnerHTML={{__html:this.state.title}}></div>
7.父子组件传值小技巧
使用情况:如果要传值的类型为Object并且想要在子组件中使用this.props获取的情况可以使用…运算符来传值
{
this.state.todos.map(todo=>{
return <Header {...todo}></Header>
})
}
8.ref使用的几种方法
第一种:ref回调函数
inputChange = ()=>{
console.log(this.inputValue.value);
}
<input
ref={child=>this.inputValue=child}
onChange={this.inputChange.bind(this)}
/>
第二种:React.createRef()
constructor(){
super();
this.inputRef = React.createRef();
}
inputChange = ()=>{
console.log(this.inputRef.current.value);
}
<input
ref={this.inputRef}
onChange={this.inputChange.bind(this)}
/>
9.React生命周期
说明:
1)getDerivedStateFromProps
返回一个对象以更新状态,或者返回null则不更新任何内容
static getDerivedStateFromProps(props, state){
return {name:props.name};
}
render() {
let {name} = this.state;
return (
<div>
{name}
</div>
)
}
2)shouldComponentUpdate
返回true则表示渲染更新状态,返回false则不重新渲染;一般用于解决重复多次渲染问题,第二种解决多次渲染问题同样可以使用继承React.PureComponent。
shouldComponentUpdate(nextProps,nextState){
return nextProps.checked !== this.props.checked .;
}
10.全局挂载方法
使用React.Component.prototype来实现全部挂载
被全局挂载的方法:
import axios from 'axios';
let ajax = axios.create({
baseURL: 'https://jsonplaceholder.typicode.com/'
});
export const getTodos = ()=>{
return ajax.get('/todos');
}
实现全局挂载:
import * as getTodos from './service/index';
React.Component.prototype.http = getTodos;
使用全局挂载:
componentDidMount(){
this.http.getTodos().then((result)=>{
console.log(result);
})
}
11.react-hooks
作用:不通过编写类组件的情况下,可以在组件内部使用状态(state) 和其他 React 特性(生命周期,context)的技术
import React,{useState,useEffect} from 'react';
const Counter = ()=>{
// 相当于给count赋值为0
const [count,setCount]=useState(0);
// 相当于ComponentDidMount和ComponentDidUpdate
useEffect(()=>{
console.log('useEffect')
})
return(
<div>
<button onClick={()=>{setCount(count-1)}}>-</button>
<span>{count}</span>
<button onClick={()=>{setCount(count+1)}}>+</button>
</div>
)
}
12.Context
作用:Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。
import React,{Fragment,createContext} from 'react';
import ReactDOM from 'react-dom';
const {Provider,Consumer:CounterConsumer} = createContext();
class CounterProvider extends React.Component{
constructor(){
super();
this.state={
count:1000
}
}
increment = ()=>{
this.setState({
count: this.state.count+1
})
}
decrement = ()=>{
this.setState({
count: this.state.count-1
})
}
render(){
return(
<Provider value={
{
count:this.state.count,
onIncrement:this.increment,
onDecrement:this.decrement
}
}>
{this.props.children}
</Provider>
)
}
}
class App extends React.Component{
render(){
return (
<Fragment>
<CountBtn type='decrement'>-</CountBtn>
<Counter />
<CountBtn type='increment'>+</CountBtn>
</Fragment>
)
}
}
class CountBtn extends React.Component{
render(){
return (
<CounterConsumer>
{
({onIncrement,onDecrement})=>{
const handleClick = this.props.type==='increment'?onIncrement:onDecrement;
return <button onClick={handleClick}>{this.props.children}</button>
}
}
</CounterConsumer>
)
}
}
class Counter extends React.Component{
render(){
return (
<CounterConsumer>
{
(args)=>{
return <span>{args.count}</span>
}
}
</CounterConsumer>
)
}
}
ReactDOM.render(
<CounterProvider>
<App />
</CounterProvider>
,
document.getElementById('root')
)
13.高阶组件HOC
高阶组件是参数为组件,返回值为新组件的函数。
高阶组件:
import React from 'react';
let copyRight = (App)=>{
return (
class CopyRight extends React.Component{
render(){
return (
<div>
<App {...this.props} />
<h1>这里是高阶组件</h1>
</div>
)
}
}
)
}
export default copyRight;
使用高阶组件:
import React, { Component } from 'react'
import CopyRight from './copyRight';
import Another from './another';
class App extends Component {
render() {
return (
<div>
<h1>这是App组件</h1>
<Another name='wq' />
</div>
)
}
}
export default CopyRight(App);
改为装饰器的写法:
步骤:
1)npm install react-app-rewired --save-dev
react-app-rewired:在不使用’eject’且未创建react-scripts分支的情况下,调整create-react-app webpack配置。
2)修改package.json文件:
修改:
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
为:
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-scripts eject"
},
3)在根目录下新建config-overrides.js
const { override, addDecoratorsLegacy } = require('customize-cra');
module.exports = override(
addDecoratorsLegacy()
);
4)npm install customize-cra --save-dev
// 将类和对象装饰器编译为ES5
npm install @babel/plugin-proposal-decorators --save-dev
高阶组件装饰器写法:
import React, { Component } from 'react'
import CopyRight from './copyRight';
@CopyRight
class Another extends Component {
render() {
return (
<div>
<h3>作者:{this.props.name}</h3>
</div>
)
}
}
export default Another;
14.状态管理
搭建简单的redux
index.js文件
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
import store from './store';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
store.js文件
import {createStore,applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import rootReducers from './reducers/index';
export default createStore(
rootReducers,
applyMiddleware(thunk), // 解决异步action问题
)
reducers.index文件
import { combineReducers } from 'redux';
import BlogListReducer from './BlogList';
export default combineReducers({
BlogListReducer,
})
使用redux
import React, { Component } from 'react'
import {connect} from 'react-redux';
import * as actions from '../../actions/BlogList';
class BlogList extends Component {
componentDidMount(){
this.props.startFetchData();
}
render() {
let {blogList} = this.props;
return (
<div>
{
blogList.map(item=>{
return <div key={item.id}>{`用户ID:${item.userId},用户标题:${item.title}`}</div>
})
}
</div>
)
}
}
let mapStateToProps = (state)=>{
return {
blogList:state.BlogListReducer.data
}
}
export default connect(mapStateToProps,actions)(BlogList);
15.实现导出Excel
前提:npm install xlsx
import XLSX from 'xlsx';
const ws = XLSX.utils.aoa_to_sheet([['a','b'],[1,2]]);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb,ws,'SheetJS');
XLSX.writeFile(wb,'WQ.xlsx');
16.简易redux
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<button onclick="store.dispatch({type: 'JIAN', n: 1})">-</button>
<span id='count'>0</span>
<button onclick="store.dispatch({type: 'JIA', n: 1})">+</button>
</div>
</body>
<script>
const countDisplay = document.getElementById('count');
const countState = {
count: 5
}
const changeState = (state, action) => {
if (!state) {
return countState;
}
switch (action.type) {
case "JIAN":
return {
...state,
count: state.count - action.n
}
break;
case "JIA":
return {
...state,
count: state.count + action.n
}
break;
default:
return state;
}
}
const createStore = (changeState) => {
let state = null;
const getState = () => state
const listeners = []
const subscribe = (listener) => listeners.push(listener)
const dispatch = (action) => {
state = changeState(state, action)
listeners.forEach(listener => listener())
}
dispatch({})
return {
getState,
dispatch,
subscribe
}
}
const store = createStore(changeState);
const renderCount = () => {
countDisplay.innerHTML = store.getState().count
}
renderCount();
store.subscribe(renderCount)
</script>
</html>
17.判断React组件是否销毁
this.updater.isMounted(this)
18. memo useMemo useCallback
1) memo:作用相当于PureComponent
import React, { memo } from 'react'
const Child = memo(() => {
const date = new Date()
return <div>当前时间:{date.getHours()} {date.getMinutes()} {date.getSeconds()}</div>
}, (pre, next) => {
// 返回true代表不更新
return true
})
2)useMemo
const Child = memo((props) => {
const date = new Date()
return <div>当前时间:{date.getHours()} {date.getMinutes()} {date.getSeconds()}</div>
})
const Parent = () => {
const [count, setCount] = useState(0)
const [testCount, setTestCount] = useState(0)
// 只有当count发生变化时,timeoption才会变化,才会引发自组件重新渲染
const timeoption = useMemo(
()=>{
return {
count
}
},
[count]
)
return (
<div>
<p>{count}</p>
<button onClick={
() => {
setCount(count + 1)
}
}>+1</button>
<button onClick={
() => {
setTestCount(testCount + 1)
}
}>+1</button>
<Child count={timeoption} />
</div>
)
}
3)useCallback
const Child = memo((props) => {
return (
<Fragment>
<input onChange={props.onChange} />
</Fragment>
)
})
const Parent = () => {
const [text, setText] = useState('')
const onChange = useCallback(
e => {
setText(e.target.value)
},
[]
)
return (
<div>
<p>{text}</p>
<Child onChange={onChange} />
</div>
)
}
19.自定义hooks
customHooks.js
import { useState, useEffect } from 'react'
export const useWindowSizeHook = () => {
const [width, setWidth] = useState(0)
const [height, setHeight] = useState(0)
useEffect(() => {
setWidth(document.documentElement.clientWidth)
setHeight(document.documentElement.clientHeight)
}, [])
useEffect(() => {
const handleResize = () => {
setWidth(document.documentElement.clientWidth)
setHeight(document.documentElement.clientHeight)
}
window.addEventListener('resize', handleResize, false)
return () => window.removeEventListener('resize', handleResize, false)
}, [])
return [width, height]
}
import { useWindowSizeHook } from './customHooks'
const Parent = () => {
const [width, height] = useWindowSizeHook()
return (
<div>
<p>宽度:{width}</p>
<p>高度:{height}</p>
</div>
)
}
20.useReducer、useContext
import React, { useReducer, useContext, createContext } from 'react'
const CTX = createContext(null)
const reducer = (state, action) => {
switch(action.type){
case 'ADD': return state + 1;
case 'SUB': return state - 1;
default: return state;
}
}
const Child = () => {
const [ count, dispatch ] = useContext(CTX)
return (
<div>
<p>count:{count}</p>
<button
onClick={
()=>{ dispatch({ type: 'SUB' }) }
}
>-1</button>
<button
onClick={
()=>{ dispatch({ type: 'ADD' }) }
}
>+1</button>
</div>
)
}
const Parent = () => {
const [ count ] = useContext(CTX)
return (
<div>
<p>count:{count}</p>
<Child />
</div>
)
}
const App = () => {
// 第一个参数参数传入reducer,第二个参数传入初始值
const [ count, dispatch ] = useReducer(reducer, 20)
return (
<CTX.Provider value={[ count, dispatch ]}>
<Parent />
</CTX.Provider>
)
}
export default App
21.useSelector、useDispatch代替connect
目录结构:
component
action.js (1)
Form.js (2)
reducer.js (3)
store
configureStore.js (4)
reducer.js (5)
App.js (6)
index.js (7)
(1)
export const TYPE = {
UPDATA_NAME: 'UPDATA_NAME',
UPDATA_TEL: 'UPDATA_TEL'
}
export const updateTel = (tel) => ({
type: TYPE.UPDATA_TEL,
payload: {
tel
}
})
export const updateName = (name) => ({
type: TYPE.UPDATA_TEL,
payload: {
name
}
})
(2)
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { updateName, updateTel } from './action'
export default () => {
const dispatch = useDispatch()
const formData = useSelector(state => {
return state.formReducer
})
console.log('formData', formData)
return (
<div>
姓名: <input onChange={(e)=> {dispatch(updateName(e.target.value))}} /> <br />
电话: <input onChange={(e)=> {dispatch(updateTel(e.target.value))}} />
</div>
)
}
(3)
import { TYPE } from './action'
const initState = {
tel: '',
name: ''
}
export default (state, action) => {
const { type, payload } = action
if(Object.values(TYPE).includes(type)) return {...state, ...payload}
return state || initState
}
(4)
import { createStore, applyMiddleware } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import thunk from 'redux-thunk'
import reducer from './reducer'
export default () => {
const middlewares = [thunk]
const enhancers = applyMiddleware(...middlewares)
const composedEnhancers = composeWithDevTools(...[enhancers])
const store = createStore(reducer, composedEnhancers)
return store
}
(5)
import { combineReducers } from 'redux'
import formReducer from '../components/reducer'
export default combineReducers({
formReducer
})
(6)
import React from 'react'
import Form from './components/Form'
const App = () => {
return (
<Form />
)
}
export default App
(7)
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import configureStore from './store/configureStore'
import App from './App'
const store = configureStore()
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)