предисловие
Следующие примеры кода можно найти в реальных проектах, и эффект от еды вместе с проектом лучше~ Обновлено (добавлены комментарии и кейсы к некоторым отзывам других)
Строительство окружающей среды
npm install -g create-react-app //安装工具
create-react-app + 项目名称 //创建项目
npm start //启动项目
дизайн-мышление
В официальном блоге React четко указано, что React — это не MVC-фреймворк, а библиотека для построения компонентного пользовательского интерфейса, инструмент разработки внешнего интерфейса. Так что самое большее это V (view) в MVC. React не изобретает велосипед, но имеет множество прорывных инноваций, особенности которых заключаются в следующем:
- Декларативное и интуитивно понятное кодирование
- Упрощение повторно используемых компонентов
JSX написание
JSX — это формат, сочетающий Javascript и XML. React изобрел JSX, который использует синтаксис HTML для создания виртуального DOM. Когда он встречает
import './css/index.css'
class App extends Component {
//将来 生命周期
render() {
var myname = 'anna' //不是状态
var stylyobj = {
background: 'red',
fontSize: '30px'
}
return (
<div>
{10 + 20}--{myname}
{10 > 20 ? 1 : 0}
<div style={stylyobj}>111111</div>
<div style={{ background: 'yellow' }}>111111</div>
// 16版本之前 class 不支持 必须写成className
// 16版本之后 class支持 ,但是会报警告
<div className='active' >33333</div>
<div id='box' >33333</div>
</div>
)
}
}
написание компонентов
1, компоненты типа класса
import React from 'react'
import { Component} from 'react'
class Hello extends React.Component {
//将来 生命周期
render() {
return (
<div>111111
<ul>
<li>1111</li>
<li>2222</li>
<Child1/>
<Child2/>
<Child3/>
</ul>
</div>
)
}
}
//Component ===>React.Component 下面的 可以直接被引入
class Child1 extends Component{
render(){
return <div>child1</div>
}
}
2, функциональные компоненты
Функциональные компоненты не поддерживают состояние до React 16.8.
После React16.8 React Hooks поддерживают состояние и свойства.
function Child2(){
return (<div>child2
<span>22222</span>
</div>)
}
const Child3=()=><div>child3</div>
export default Hello
Четыре способа записи событий
Написание одного: небольшое количество кодаВ случае , вы можете написать прямо в этикетке
// 获取到输入框的value值
<input type = 'text' ref = 'mytext' />
<button onClick={() => {
console.log('onclick', this.refs.mytext)
}}>add</button>
правописание два:Легко передать параметры, измените это, чтобы выполнить
{/* 注意这里不能加小括号 触发的时候会自动调用 。如果加小括号 ,= 函数返回值再调用*/}
<button onClick={this.handleAdd2.bind(this)}>add2</button>
//写在 render 外面
handleAdd2(){
console.log('click22222', this.refs.mytext.value)
}
Способ записи 3: функция стрелкиНельзя передавать параметры, но ведь это удобно
<button onClick={this.handleAdd3}>add3</button>
handleAdd3=()=>{
console.log(this.refs.mytext.value)
}
Метод письма 4: Метод комбинированного письма
<button onClick={() => {
this.handleAdd3('aaa','bbbb')
}}>add4</button>
handleAdd3=(x,y)=>{
console.log(x,y,'click22222', this.refs.mytext.value)
}
Поле ввода изменяется, чтобы получить значение поля ввода:
<div>
<input type="test" onChange={(evt)=>{
console.log(evt.target.value)
}}/>
назначить поле ввода
value={this.state.mytext}
Измените это, чтобы указать на
привязать вызов применить разницу
**вызов:** Вы можете передать несколько параметров и вызвать функцию сразу после изменения указателя this.
**apply:** Вы можете передать массив и вызвать функцию сразу после изменения указателя this.
**bind:** После изменения этой точки вы можете передать несколько параметров, и возвращаемая функция не будет вызываться сразу
var obj1={
name:'obj1',
getName(){
console.log(this.name)
}
}
var obj2 = {
name: 'obj2',
getName() {
console.log(this.name)
}
}
// obj1.getName()//obj1
// 改变this指向,立即指向方法
// obj1.getName.call(obj2,'aaa','bbbb','cccc')//obj2
//obj1.getName.apply(obj2,['aaa','bbb','ccc'])//obj2
// 改变this指向,但是需要手动执行方法
//obj1.getName.bind(obj2,'aaa','bbb','ccc')()
Инициализировать состояние и изменить состояние
React рассматривает компоненты как конечные автоматы. Благодаря взаимодействию с пользователем достигаются различные состояния, а затем визуализируется пользовательский интерфейс для обеспечения согласованности пользовательского интерфейса и данных. В React просто обновите состояние компонента, а затем повторно отобразите пользовательский интерфейс на основе нового состояния (без манипулирования DOM).
Два способа записи состояния (state)
Первый полный способ записи:
export default class App extends Component {
constructor() {
super()
this.state = {
myname:'4567'
}
}
render() {
return (
<div>
{this.state.myname}
</div>
)
}
}
Второе сокращение: это состояние записи также определяется в конструкторе
export default class App extends Component {
state = {
myname:'4567'
}
render() {
return (
<div>
{this.state.myname}
</div>
)
}
}
Изменить состояние (setState)
процесс синхронизации
<button onClick={this.handkeClick}>click</button>
//直接修改状态
handkeClick=()=>{
this.setState({
myname:'xiaoming',
myage:'18'
})
}
асинхронный процесс
Первый способ записи:
Принимает два параметра:
Первый параметр — это объект, измененное значение состояния
Второй параметр можно выполнить после ожидания обновления дерева dom.
this.setState({
myname:'xiaoming'
},()=>{
console.log('1',this.state.myname)
})
之后发生什么?
//1.虚拟dom创建
//2.diff对比
Второй способ написания:
Вы можете получить последнее значение состояния (prevState) должно иметь возвращаемое значение
//1. 简写
this.setState((prevState)=>({
count: prevState.count+1
}))
// 2. 完整写法
this.setState((prevState)=>{{
count: prevState.count+1
}})
Когда setState синхронен, а когда асинхронен, почему это происходит и как React управляет синхронностью и асинхронностью?
Если вы хотите знать, вы можете прочитать этоКогда setState обновляет состояние в React, когда оно синхронно, а когда асинхронно?
траверс
Написание одного:
{ this.state.datalist.map(item => <li key={item}>{item}</li>) }
Пишем два:
var newlist = this.state.datalist.map(item => <li key={item}>{item}</li>)
{newlist} //使用变量
коммуникация
Переход от родителя к дочернему через свойства (реквизиты)
отец:
//需要 {} 包住才是 js 不然是字符串
<Navbar mytitle='home' myshow={false}></Navbar>
Sub: можно получить напрямую через имя свойства this.props.
{this.props.mytitle}
Сокращение свойства:
var obj={
mytitle:'测试',
myshow:false
}
<Navbar {...obj}></Navbar>
проверка атрибута
Доступ к Navbar.propTypes можно получить
import MyPropTypes from 'prop-types'; //提供验证数据类型的方法,必须交给MyPropTypes模块方法进行处理验证
class Navbar extends Component {
static propTypes = {
myshow: MyPropTypes.bool,
};
}
свойства по умолчанию
static defaultProps = {
myshow: true
}
сын к отцу через события
Родитель: передал функцию обратного вызова в прошлом
<Navbar onEvent={() => {
this.setState({
isShow: !this.state.isShow
})
}}></Navbar>
Sub: вызывается сразу после получения этой функции обратного вызова
<button onClick={this.handleClick}>hide/show</button>
handleClick = () => {
this.props.onEvent()
}
Ref
RefВы можете использовать его для привязки к любому выводу компонента с помощью render() .
Это специальное свойство позволяет вам ссылаться на соответствующий резервный экземпляр, возвращаемый функцией render(). Это гарантирует, что вы всегда получите правильный экземпляр.
родительский компонент: вы можете получить экземпляр компонента ввода и изменить его внутреннее значение состояния.
<Input ref='mytext' />
<button onClick={
this.handleClick
}>add</button>
handleClick = () => {
console.log(this.refs.mytext.state.mytext)// 拿到值
this.refs.mytext.reset() // 清空输入框
}
Подсборка:
class Input extends Component {
state = {
mytext: ''
}
reset = () => {
this.setState({
mytext: ''
})
}
<div>
<div>others input</div>
<input value={this.state.mytext} type='text' style={{ background: 'yellow' }} onChange={(ev) => {
this.setState({
mytext: ev.target.value
})
модель публикации-подписки
Напишите самостоятельно модель публикации-подписки для передачи информации
**Шина событий**. Используется для наблюдения за подписчиками и издателями. Если обнаружится, что издатель отправил информацию, информация будет немедленно отправлена подписчику.
const EventChannel = {
list: [],
subscribe(callback) {
this.list.push(callback)
},
dispatch(data) {
this.list.forEach(item => {
item(data)
})
}
}
подписчик: хранит свои собственные обратные вызовы в шине событий, а шина событий проходит через вызов. Издатель вызывает метод публикации и может передать собственные параметры издателя, а подписчик может их получить.
class Child3 extends Component {
// 创建成功 ,dom挂载完成
componentDidMount() {
observer.subscribe((data) => {
console.log('child3定义的callback', data)
})
// console.log('componentDidMount', '调用订阅方法', observer.subscribe())
}
render() {
return <div style={{ background: 'blue' }}>我是微信用户</div>
}
}
class Child3 extends Component {
// 创建成功 ,dom挂载完成
componentDidMount() {
observer.subscribe((data) => {
console.log('child3定义的callback', data)
})
// console.log('componentDidMount', '调用订阅方法', observer.subscribe())
}
render() {
return <div style={{ background: 'blue' }}>我是微信用户</div>
}
}
**Publisher:** вызвать метод публикации шины событий.
метод выпуска: Обход обратного вызова абонента и вызов его.Вы можете передать свои параметры в середине обхода.
class Child2 extends Component {
render() {
return <div style={{ background: 'red' }}>公众号发布者
<button onClick={this.handleClick}>发布</button>
</div>
}
handleClick=()=>{
EventChannel.dispatch('child2的问候')
}
}
контекстная коммуникация
** База: ** Укажите свое собственное состояние и способ его изменения.
Базовый код:
export default class App extends Component {
state = {
text: '私人服务'
}
changeState=(data)=>{
this.setState({
text: data
})
}
render() {
return (
<GlobalContext.Provider value={{
sms: '短信服务',
call: '电话服务',
text: this.state.text,
changeState:this.changeState
}}>
<div>
<Child1></Child1>
</div>
</GlobalContext.Provider >
)
}
}
**Корреспондент:** Вызвать модифицированный базой метод и передать свою информацию
class Child2 extends Component {
render() {
return <GlobalContext.Consumer>
{context => (
<div style={{ background: 'blue' }}>child2--{context.call}
<button onClick={() => this.handClick(context)}>child2通信</button>
</div>
)
}
</GlobalContext.Consumer>
}
handClick = (context) => {
context.changeState('来自child2的问候')
console.log(context)
}
}
другие корреспонденты: как только состояние изменится, вы можете получить его немедленно
class Child1 extends Component {
render() {
return <GlobalContext.Consumer>
{context => (
<div style={{ background: 'yellow' }}>child1--{context.text}</div>
)
}
</GlobalContext.Consumer>
}
}
Жизненный цикл
Компонент проходит следующие три этапа по порядку: этап инициализации, этап выполнения, этап уничтожения.
Три жизненных цикла скоро будут заброшены и не рекомендуются к использованию.Два новых жизненных цикла были добавлены на замену~
фаза инициализации
componentWillMount
Последний шанс изменить состояние перед рендерингом, вызываемый перед рендерингом, на стороне клиента и на стороне сервера,
Он вот-вот будет объявлен устаревшим, и использовать его не рекомендуется.После версии 17 необходимо добавить в работу UNSAFE_(UNSAFE_componentWillMount),
Причина отказа:
В ssr этот метод будет вызываться несколько раз, поэтому он будет срабатывать несколько раз.В то же время, если событие привязано сюда, оно не сможет отвязаться, что приведет к утечкам памяти и станет небезопасным и эффективным и постепенно отброшенный
UNSAFE_componentWillMount(){
console.log('componentWillMount','ajax',)
}
render
Доступны только this.props и this.state, state и dom нельзя изменять, и они будут вызываться несколько раз в жизненном цикле.
componentDidMount
Запускается после успешного рендеринга и рендеринга реального дома, дом может быть изменен, и в этом жизненном цикле будут записаны общие данные запроса.
componentDidMount() {
console.log('componentDidMount', 'ajax 绑定')
fetch("/test.json").then(res=>res.json()).then(res=>{
console.log(res.data)
this.setState({
list: res.data.films
})
})
}
рабочая фаза
componentWillReceiveProps
Триггер атрибута модификации родительского компонента (используемый дочерним компонентом) будет срабатывать несколько раз, вы можете получить идентификатор здесь
Вскоре будет объявлено устаревшим, не рекомендуется, UNSAFE_ необходимо добавить после версии 17 для работы (UNSAFE_componentWillReceiveProps)
Причина отказа:
Внешние компоненты часто обновляются и передаются в нескольких разных свойствах, что приводит к ненужным асинхронным запросам.
Этот жизненный цикл имеет новую замену жизненного цикла - **getDerivedStateFromProps ** Вы можете увидеть введение позже ~
// 会走多次 可以在这里获取到id 更新 mount 只会走一次
UNSAFE_componentWillReceiveProps(nextProps) {
console.log('componentWillReceiveProps')
console.log('获取到ajax数据', nextProps.myname)
}
shouldComponentUpdate
** Возврат false предотвратит вызов рендеринга **
Вы можете выполнять функции настройки производительности.Вы можете получить новое состояние и старое состояние, а затем сравнить состояние.Если состояние не изменилось, оно не будет повторно отображаться.
shouldComponentUpdate(nextProps, nextState) {
// 性能调优函数 //新的状态和老的状态
console.log('shouldComponentUpdate',this.state.myname,nextState.myname)
if (this.state.myname !== nextState.myname){
return true //返回 true 会自动渲染 这个是手动自己去对比 dom 是否发生改变再去调用 render
// react有自动优化能力 —— PureComponent(看后面~)
}
return false //false 不会重新渲染
}
componentWillUpdate
Изменение свойств и состояний запрещено, оно будет срабатывать несколько раз и вскоре будет удалено.
Причина отказа:
Запишите состояние DOM перед обновлением, и может быть выполнена некоторая обработка.Если временной интервал от componentDidUpdate слишком длинный, состояние будет ненадежным, и будет новый жизненный цикл——getSnapshotBeforeUpdate заменяет
UNSAFE_componentWillUpdate(){
console.log('componentWillUpdate')
}
render
Доступны только this.props и this.state, состояние и dom нельзя изменять, и они будут вызываться несколько раз в жизненном цикле.
componentDidUpdate
Вызывается сразу после завершения обновления компонента, не будет вызываться во время инициализации, может изменять dom
фаза разрушения
componentWillUnmount
Вызывается непосредственно перед удалением компонента из модели DOM для выполнения операций очистки, таких как таймеры и прослушиватели событий, перед удалением компонента.
Два недавно добавленных жизненных цикла
getDerivedStateFromProps
Синхронизация:
1. Вы можете изменить старое состояние
2. Будь то инициализация или обновление, вы можете получить свойства родительского компонента
componentWillReceiveProps(nextProps) //改变才会获取到属性
// 里面不能用this 必须用static
static getDerivedStateFromProps(nextprops, state) {
//初始化属性 和更新属性都可以获取到
document.title = nextprops.mytitle
console.log(nextprops, state)
return null //状态不改变
return {
myname: state.myname.substring(0, 1).toUpperCase()
} //返回一个新的状态 可以在次修改状态
}
Асинхронное действие:
Запросы Ajax нельзя делать в getDerivedStateFromProps, его необходимо использовать в сочетании с другими жизненными циклами.
componentDidMount() {
console.log('发ajax', this.state.myid)
}
// componentWillReceiveProps() {
// console.log('发ajax')
// }
static getDerivedStateFromProps(nextprops, state) {
console.log('getDerivedStateFromProps','获取到id值', nextprops.id)
return {
myid: nextprops.id
}
}
getSnapshotBeforeUpdate
Может получить статус перед обновлением
//data 接收到了getSnapshotBeforeUpdate的返回值
componentDidUpdate(prevProps, prevState,data) {
console.log('componentDidUpdate', data)
}
// 在render 生命之后 在已经更新完之前 可以准确获取 返回之后的状态
// componentDidUpdate第三个参数可以获取到这个值
getSnapshotBeforeUpdate = (prevProps, prevState) => {
console.log('getSnapshotBeforeUpdate','获取滚动条的位置')
return {
y:100
}
}
Решения для оптимизации производительности в React
1. долженобновить компонент
Ручное управлениеНужно ли обновлять сам компонент или подкомпоненты, особенно когда их много, это не подходит для этого решения.
2. Чистый компонент
PureComponent предоставляется ReactАвтоматическая оптимизация, поможет вам сравнить новый реквизит со старым реквизитом,
В зависимости от того, равны ли значения (равны значения или объекты имеют одинаковые свойства и значения свойств равны), решить, возвращает ли shouldComponentUpdate значение true или false, и, таким образом, решить, вызывать ли рендеринг функция
**Преимущества:** Это может сократить выполнение повторяющихся жизненных циклов и автоматически сравнивать виртуальный дом и т. д.
** Недостатки: ** Если ваше состояние или реквизиты «изменяются навсегда», PureComponent не будет быстрее, потому что smallEqual также требует времени, если компонент необходимо обновлять в режиме реального времени, вы можете использовать shouldComponentUpdate
import React, { Component, PureComponent } from 'react'
export default class App extends PureComponent {}
слот
this.props.children получает массив контента
Дочерний компонент:
const Child = (props)=>{
return <div>
child--{props.children}
</div>
}
Используйте этот компонент:
export default function App() {
return (
<div>
{/* 插槽 */}
<Child>
<li>11111</li>
<li>222222</li>
</Child>
</div>
)
}
маршрутизация
Установить:
cnpm i --save react-router-dom
В режиме HashRouter будут предупреждены несколько точек одного и того же маршрута.
решение: Перейти в режим истории : BrowserRouter
Пишу:
React-router-dom версии 4.5 написан так же:
//
import {
HashRouter as Router, //路由外层需要包裹的组件 hash模式
// BrowserRouter(后端配置 history 模式)
Route ,//每个路由组件都需要此组件
}from 'react-router-dom'
import React from 'react'
import Home from '../views/home/Home'
import Login from '../views/login/Login'
// class BlogRouter extends Comment{
// }
** Написание функционального компонента: **
const BlogRouter=()=>(
<Router>
<Route path='/home' component={Home}/>
<Route path='/login' component={Login}/>
</Router>
)
export default BlogRouter
app.js
import BlogRouter from './router'
class App extends Component{
render(){
return(
<div>
<BlogRouter/>
</div>
)
}
}
export default App;
Вложенные маршруты
Существует два способа написания вложенных маршрутов:
1. Пишем прямо в родительском компоненте:
import { Route} from 'react-router-dom'
import Right from './Right'
import Role from './Role'
export default class Manage extends Component {
render() {
return (
<div>
<ul>
<li>权限列表</li>
<li>角色列表</li>
<Route path='/right-manage/right' component={Right} />
<Route path='/right-manage/roles' component={Role} />
</ul>
</div>
)
}
}
- В маршруте напишите:
import Manage from '../views/rightmanage/Manage'
import Right from '../views/rightmanage/Right'
import Role from '../views/rightmanage/Role'
<Route path='/right-manage' render={()=>
(<Manage>
<Switch>
<Route path='/right-manage/rights' component={Right} />
<Route path='/right-manage/roles' component={Role} />
<Redirect from='/right-manage' to='/right-manage/roles' />
</Switch>
</Manage>)
}/>
** Оставьте отверстие в родительском компоненте: **
{this.props.children}
перенаправление маршрута
** Должен включать переключатель ** После сопоставления он не будет продолжать совпадать, он сразу выпрыгнет
import {
Route,
Redirect,//重定向
Switch//匹配到第一个符合条件路径的组件,就停止了
} from 'react-router-dom'
export default class DashBorad extends Component {
render() {
return (
<div>
<div>顶部导航栏</div>
<Switch>
{/* 重定向 */}
<Redirect from='/' to='/home' exact />
<Route path='*' component={Notfind} />
</Switch>
</div>
)
}
}
Страница перехода
Прыжок рендеринга маршрута:
<Route path='/artic-manege/preview/:myid' component={Prebiew} />
Программно переходить страницы:
this.props.history.push(`/artic-manege/preview/${id}`)
Получить переданное значение:
this.props.match.params.myid
Компоненты высшего порядка (с маршрутизатором)
Компоненты высокого порядка, получить компоненты низкого порядка, сгенерировать компоненты высокого порядкаМожет реализовать переход и очистку пакета маршрутизацииЖдать
Некоторые компоненты не окружены маршрутизатором и не получат this.props , вы можете обернуть их компонентами более высокого порядка, а затем получить их this.props
import {withRouter} from 'react-router' //路由
//获取到 this.props 跳转至 home
this.props.history.push('/home')
export default withRouter(SideMenu)
Не удается получить решение this.props
Помимо использования метода компонентов более высокого порядка, вы также можете использоватьРодительский компонент передает this.props дочернему компоненту
Родительский компонент:
annahistory={this.props.history}
Сборка:
this.props.kerwinhitory.push(obj.key)
Redux
Redux в основном используется для управления состоянием приложения, то есть Redux поддерживает состояние всего приложения с помощью одного постоянного дерева состояний (объекта), которое нельзя изменить напрямую. Если некоторые данные изменяются, создается новый объект (с использованием действий и редюсеров).
Рабочий процесс Redux:
синхронное письмо
файл store.js:
import {createStore} from 'redux'//createStore 方法创建一个store回想
// 创建一个reducer ,
//'修改状态'(接收老状态,修改的值,深复制之后,再返回一个新的状态)
const reducer=(prevState={
// 设置一个初始值
iscollapsed:false
},action)=>{
console.log(action)
// 深复制一份新的把action里面获取的值 返回出去
var newstate={...prevState}
newstate.iscollapsed=payload
return newstate
}//只要状态已返回,会自动更新
const store=createStore(reducer)
export default store
Издатель (опубликовать собственный статус)
store.dispatch({
type:'mysideMenuCollapsed',
payload: iscollapsed
});//store 在action里面可以获取到发布者的值
Подписчики (которые вносят изменения, хотят получить новый статус)
componentDidMount() {
// 订阅 注意一定要取消订阅
this.unscribe= store.subscribe(()=>{
//store.getState() 这个可以获取到新的状态
console.log('有人通知我更新了',store.getState())
this.setState({
collapsed: store.getState().iscollapsed
})
})
}
componentWillUnmount(){
// 取消订阅
this.unscribe()
}
Асинхронная запись
Промежуточное ПО для асинхронных действий
1. редукционный преобразователь
redux-thunk может вернуть функцию в actionCreator, выполнить функцию и передать в эту функцию два параметра отправки и getState, мы можем отправить в любое время
store.js:
import { createStore ,applyMiddleware} from 'redux'//createStore 方法创建一个store回想
import reduxThunk from 'redux-thunk'
// 创建一个reducer ,
//'修改状态'(接收老状态,修改的值,深复制之后,再返回一个新的状态)
const reducer = (prevState = {
// 设置一个初始值
roleList:[]//角色侧边导航数据
}, action) => {
let { type, payload } = action
switch (type) {
case 'setRoleList':
// 深复制 不能在prevState(老状态上直接修改)需要返回一个新的状态
var newstate = { ...prevState }
newstate.roleList= payload
return newstate
default :
return prevState
}
}//只要状态已返回,会自动更新
// 默认 action 只能是普通对象{type:''}
// 创建store 顺便应用中间件thunk 如果action是函数,我来处理
const store = createStore(reducer,applyMiddleware(reduxThunk))
export default store
Случай подписчика и издателя:
роль.js:
actionCreater = () => {
// middleware 解决异步处理redux-thunk redux-promise
return (dispatch) => {
axios.get("http://localhost:8000/roles").then(res => {
console.log(res.data)
// 自己决定什么时候发送
dispatch({
type: 'setRoleList',
payload: res.data
})
})
}
}
componentDidMount() {
if (store.getState().roleList.length == 0) {
//发ajax
store.dispatch(this.actionCreater())
} else {
console.log('使用缓存', store.getState().roleList)
this.setState({
datalist: store.getState().roleList
})
}
//数据改变了 订阅获取到新的数据
this.unscribe = store.subscribe(() => {
console.log("请求数据结束", store.getState().roleList)
this.setState({
datalist: store.getState().roleList
})
})
}
componentWillUnmount() {
// 取消订阅
this.unscribe()
}
2. сокращение-обещание
redux-promise может вернуть объект обещания в actionCreator, он дождется успеха и отправит успешный результат
store.js
import reduxPromise from 'redux-promise'
import { createStore, applyMiddleware } from 'redux'//createStore 方法创建一个store回想
const reducer = (prevState = {
// 设置一个初始值
rightList: [],//角色侧边导航数据
}, action) => {
console.log(action)
// 深复制
let { type, payload } = action
switch (type) {
case 'setRightsList':
var newstate = { ...prevState }
newstate.rightList = payload
return newstate
default:
return prevState
}
}//只要状态已返回,会自动更新
const store = createStore(reducer, applyMiddleware(reduxPromise))
export default store
Случай подписчика и издателя:
роль.js:
actionCreater = () => {
// 返回一个promise对象
return axios.get("http://localhost:8000/rights").then(res => {
return {
type: 'setRightsList',
payload: res.data
}
})
}
componentDidMount() {
if (store.getState().rightList.length == 0) {
//发ajax
store.dispatch(this.actionCreater()).then(data=>{
this.setState({
datalist: store.getState().rightList
})
})
} else {
console.log('使用缓存', store.getState().rightList)
this.setState({
datalist: store.getState().rightList
})
}
}
Core API-Reducer
Редюсеры гарантированно будут чистыми функциями
чистая функция
1. Функции, не имеющие побочных эффектов для внешнего мира
2. Тот же вход, тот же результат
var myname='anna'
function test(myname){
myname='xiaoming'
}
test(myname)
Нечистая функция:
var myname='anna'
function test(){
myname='xiaoming'
}
test()
расколоть
Редуктор можно разделить по бизнес-модулям
store.js
import { createStore, applyMiddleware ,combineReducers} from 'redux'//createStore 方法创建一个store回想
import reduxThunk from 'redux-thunk'
import reduxPromise from 'redux-promise'
import collapseReducer from './reducers/collapseReducer'
import rightListReducer from './reducers/rightListReducer'
import roleListReducer from './reducers/roleListReducer'
const reducer = combineReducers({
iscollapsed: collapseReducer,
roleList: roleListReducer,
rightList: rightListReducer
})
const store = createStore(reducer, applyMiddleware(reduxThunk, reduxPromise))
export default store
collapseReducer
const collapseReducer = (prevState = false, action) => {
let { type, payload } = action
switch (type) {
case 'sideMenuShow':
return payload
default:
return prevState
}
}
export default collapseReducer
roleListReducer.js
const roleListReducer = (prevState =[], action) => {
let { type, payload } = action
switch (type) {
case 'setRoleList':
var newstate = { ...prevState }
newstate = payload
return newstate
default:
return prevState
}
}//只要状态已返回,会自动更新
export default roleListReducer
React-Redux
синхронное письмо
app.js
import { Provider } from 'react-redux'
import store from './redux/store
<Provider store={store}>
<BlogRouter/>
</Provider >
диктор
Сопоставьте методы со свойствами с помощью
Первый параметр — это согласованный атрибут, передаваемый дочернему элементу.
Второй параметр сопоставляет метод со свойством с
import { connect } from 'react-redux'
const mapStateToprops=()=>{
return {
}
} //state 映射成属性用
const mapDispathToProps={
actionCreator:(iscollapsed)=>{
return {
type: 'sideMenuShow',
payload: iscollapsed
}
}
}
export default withRouter(connect(mapStateToprops,mapDispathToProps)(TopHeader))
Подписчики получают
import { connect } from 'react-redux'
const mapStateTopprops=(state)=>{
return {
iscollapsed:state.iscollapsed
}//约定isCollapsed 属性
}
export default withRouter(connect(mapStateTopprops)(SideMenu))
асинхронный
if (this.props.datalist.length == 0) {
//直接调用改方法 会把状态传递给redux
this.props.setList()
}
//订阅者 state 中可以获取到redux中的状态
const mapStateToprops = (state) => {
return {
datalist:state.rightList
}
} //state 映射成属性用
//会自动传递给redux
const mapDispathToProps = {
setList : () => {
// 返回一个promise对象
return axios.get("http://localhost:8000/rights").then(res => {
// 自己决定什么时候发送
return {
type: 'setRightsList',
payload: res.data
}
})
}
}
// } //把方法映射成属性用
export default connect(mapStateToprops,mapDispathToProps)(Right)
Redux и отношения React-Redux
mobx
Mobx — это мощный и простой в использовании инструмент управления состоянием.
1. Коробочный метод
Может наблюдать только простые типы данных
store.js
import { observable } from 'mobx'
const store = observable.box(true)
export default store
// 传播者
import store from '../../mobx/store'
store.set(false)
// 接收者
import store from '../../mobx/store'
import { autorun } from 'mobx'
autorun(() => {
console.log(store.get())
})
2. метод карты
Соблюдайте сложные типы данных
const store = observable.map({
isshow:true,
list:[],
roleList:[],
rightList:[]
})
store.set('isshow',false)
Преимущества мобкса:
- Стиль письма мобокса больше склонен к упу
- mobox напрямую изменяет часть данных, не всегда возвращая новые данные
- mobox это не один магазин. может хранить несколько
- Redux по умолчанию хранит данные в виде нативных объектов JavaScript, а для наблюдения за объектами можно использовать mobx.
Недостатки мобкса:
Существует очень мало соглашений и кодов шаблонов, предоставляемых mobx, и код очень свободен для написания.Если некоторые соглашения не выполняются, это легко может привести к непоследовательному стилю кода команды.
Несколько связанных промежуточных программ, проблема бизнес-интеграции логического уровня
обнаруженные ошибки
Первая ошибка:
**
**
решение:
отменить наблюдение
this.cancel = autorun(() => {
this.setState({
code: store.get('isshow')
}
//取消观察
componentWillUnmount() {
this.cancel()//取消观察
}
Второй баг:
**
**
решение:
Когда скорость сети очень низкая, данные не возвращаются, а данные, запрошенные ajax, не возвращаются.
componentWillUnmount() {
this.setState=()=>{}
console.log('列表销毁','取消ajax')
}
React Hooks
Hook— новая функция в React 16.8. Он позволяет использовать состояние и другие функции React без написания классов.
useState написание
import React,{useState}from 'react'
export default function App() {
const [name, setName] = useState('anna')//初始值[状态,改变状态的方法]
const [age, setAge] = useState('12')//初始值[状态,改变状态的方法]
return (
<div>
app-{name}-{age}
<button onClick={()=>{
setName('xiaoming')
setAge('18')
}}>click</button>
</div>
)
}
получить ссылку
import React, { useState, useRef }from 'react'
const mytext = useRef(null)
<input type='text' onChange={(ev)=>{
settext(ev.target.value)
}} ref={mytext}/>
событие щелчка
<button onClick={() => handleDeleClick(index)}>dele</button>
const handleDeleClick=(index)=>{
console.log(index)
var newlist=[...list]
newlist.splice(index,1)
setlist(newlist)
}
Альтернатива сложному жизненному циклу (useEffect)
Формат: useEffect (обработчик, [зависимость])
Если зависимости передается пустой массив, эквивалентный componentWillMount , он будет выполнен только один раз перед монтированием.
Если второй параметр не передан, это означает, что любое изменение состояния будет выполнено повторно.
useEffect(()=>{
},[])
**Обновление: [зависимость] будет выполняться только один раз, если зависимость изменится**
// age 更新会重新执行
useEffect(()=>{
console.log('创建或更新')
},[age])
создать/уничтожить
useEffect(() => {
var id=setInterval(() => {
console.log(111)
}, 1000);
console.log('创建')
return () => {
// cleanu
clearInterval(id)
console.log('销毁')
}
}, [])
получить реквизит
export default function Prebiew(props) {}
useCallback повышает эффективность работы
Предотвратите повторное создание методов из-за повторного рендеринга компонентов и улучшите производительность.
const test=useCallback(
() => {
console.log(text)
},
[text]
)//闭包,缓存函数,提高性能
test()
useReducer и useContext
Функция useReducer, представленная в хуках, может улучшить функцию ReducerDemo, чтобы предоставить функции, аналогичные Redux.После того, как useReducer введен, useReducer принимает функцию редуктора в качестве параметра, а редюсер принимает два параметра, один — состояние, а другой — действие. Затем верните счетчик состояний и dispath, count — это значение в возвращаемом состоянии, а dispatch — это событие, которое может публиковать события для обновления состояния.
reducer.js
const reducer = (prevstate, action) => {
let { type, payload } = action
switch (type){
case "Change_text":
// 深复制
return {
...prevstate, text: payload
}
case "Change_list":
// 深复制
return {
...prevstate, list: payload
}
}
return prevstate
}
export default reducer
index.js (глобальный контекст)
index.js (GlobalContext )
import React from 'react'
const GlobalContext = React.createContext()
export default GlobalContext
app.js
import GlobalContext from './store/index'
import reducer from './store/reducer'
import React ,{useReducer,useContext}from 'react'
const App=() =>{
// 表示reducer 传入初始值 代表reducer管理这些状态
const [state, dispatch] = useReducer(reducer, {
isShow: true,
list: [],
text: "我是公共的状态"
}) //[公共的状态,改变公共状态的方法]
return <GlobalContext.Provider value={{
state,
dispatch
}}>
<Child1/>
</GlobalContext.Provider>
}
//获取到app传来的信息 state可以直接获取到 dispatch 可以进行修改状态
const Child1=()=>{
let { state, dispatch } = useContext(GlobalContext) //不需要consumer
// console.log(useContext(GlobalContext))
return <div>
//同步:
child1-{state.text}<button onClick={()=>{
dispatch({type:'Change_text',
payload:'child1111111'
})
}}>click</button>
</div>
// 异端:
axios.get("http://localhost:8000/users").then(res=>{
console.log(res.data)
dispatch({
type: 'Change_list',
payload: res.data
})
})
}
Пользовательские крючки
** Когда мы хотим разделить логику между двумя функциями, мы можем извлечь ее в третью функцию **
Должен ли он начинаться с «использовать»?
Так и должно быть. Это соглашение очень важно.Если вы не будете следовать ему, React не сможет автоматически определить, нарушают ли ваши хуки правила хука, потому что он не может определить, содержит ли функция вызов своего внутреннего хука.
//为preview 组件提供数据
const usePrebiewDate = (props)=>{
const [title, settitle] = useState('')
const [content, setcontent] = useState('')
const [category, setcategory] = useState([])
useEffect(() => {
axios.get(`http://localhost:8000/articles/${props.match.params.myid}`).then(res => {
console.log(res.data)
let { title, category, content } = res.data
settitle(title);
setcontent(content);
setcategory(category);
})
return () => {
}
}, [props])
return {
title,
content,
category
}
}
let { title, content, category}= usePrebiewDate(props)
настоящий бой
Система фонового управления для управления статьями——адрес
Некоторая логика проекта будет обновлена позже ~ Если у вас есть какие-либо вопросы по поводу вышеуказанного контента, вы можете связаться со мной ~ Я отвечу вовремя, когда вы его увидите.
Справочная статья
Когда setState обновляет состояние в React, когда оно синхронно, а когда асинхронно?
Освоение React — useReducer