这是一篇比较全面讲解 React 的文章,里面不少基础知识但愿你本身一边查阅资料一边学习。全文从业务开发中最经常使用见 loading 效果不一样是实现讲起,说下如今前端开发在业务上应该有的思考。html
最简单的实现,咱们在 Loading 组件内部声明一个状态,经过代码逻辑判断 loading 效果的展现。前端
export default class extends Component { ... render() { return this.state.loading ? <div className="loader" /> : <div>finish</div>; } }
完整演示react
随着业务的发展,这个 Loading 组件用到的地方会很是多,上面这个代码耦合了不少逻辑,为了让这个组件可以很好的复用,那咱们抽离出组件的业务逻辑,将内部状态进行提高,那这个组件就是一个能被复用的 UI 组件。git
export default function(props) { return props.loading ? <div className="loader" /> : <div>finish</div>; }
完整演示github
注:上面两段代码你可能会想,为何 Func
和 Class
都能实现一个组件,他们有什么差异吗?
其实你在开发时不容易感受到差异,但 React 自己是进行了不少差异处理,若是是 Class 类,React 会用 new
关键字实例化,而后调用该实例的 render
方法,若是是 Func 函数,React 会直接调用它。编程
若是你是一个 jQuery 转型 React 的开发,会很天然的想到,我找到 Loading 组件的节点,控制他的显示与隐藏,固然这也是能够的,React 提供 Refs 方便你访问 DOM 节点 或 React 元素。redux
export default class extends Component { componentDidMount() { fetch().then(() => { this.el.changeLoading(false); }); } render() { return ( <Loading ref={el => { this.el = el; }} /> ); } }
完整演示前端框架
当你的应用作到必定的复杂度,不一样的页面都会有 loading 效果,你确定不但愿每一个页面都重复的书写同样的逻辑,这样会致使你的代码重复且混乱。框架
React 中有两个比较常见的解决方案 HOC
和 Render Props
,其实这两个这两个概念都是不依赖 React 的。dom
让咱们暂时忘掉 React,下面我对 HOC
和 Render Props
写两个例子,你会发现组件复用是如此简单。
HOC 其实就是一种装饰器模式,它接受一个组件做为参数,而后返回相同的组件,这样就能够额外增长一些功能。
const func = () => { console.log("func"); }; const wrap = func => { console.log("wrap"); return func; }; // wrap 逻辑已被复用 wrap(func)();
Render Props 就是咱们给一个函数传递一个回调函数作为参数,该回调函数就能利用外面函数的执行结果作为参数,执行任何操做。
const func = param => { console.log("func"); }; const wrap = (param, func) => { console.log("wrap"); func(param); }; // wrap 逻辑已被复用 wrap("", func);
相同点:
重用组件逻辑
;回调地狱
。不一样点:
总的来讲,在须要复用组件逻辑的时候,我我的更倾向于 Render Props 的方式。
当你的应用愈来愈大,组件之间交互愈来愈复杂,那整个页面的数据逻辑将变得难以管理,这时候为了方便管理应用的状态,你能够选择一些状态管理工具,例如 Redux、Flux、dva 等。
我不太想谈这些数据流框架,由于他们的概念 action
、store
、dispatch
太过于生涩难懂。
现代前端框架 React 和 Vue 其实都是一个套路,经过数据渲染试图,而后视图上操做反过来更新数据,从新渲染视图,刷新页面。
数据叫作 store
,动做叫作 ation
,触发行为叫 dispatch
,而后数据到视图的渲染由 React/Vue 处理的。
(图片来自 这里)
// reducers.js const initialState = { loading: false }; export default function reducer(state = initialState, action) { switch (action.type) { case "CHANGE_LOADING": return { loading: action.payload }; default: return state; } }
当你代码中有大量的异步操做时,例如 fetch 请求,你确定会想到事件监听
、回调函数
、发布/订阅
。
很好,上一个例子其实就是事件监听
的处理方式,而后回调函数
的主流的解决方案是 redux-thunk,而发布/订阅
的主流解决方案是 saga。
import { takeLatest, put } from "redux-saga/effects"; import fetch from "./fetch"; function* fetchInfo(action) { yield put({ type: "CHANGE_LOADING", payload: true }); yield fetch(); yield put({ type: "CHANGE_LOADING", payload: false }); } export default function* fetchSaga() { yield takeLatest("FETCH_REQUEST", fetchInfo); }
当你耐心看到这里,我知道你对 React 确定有必定的经验,如今还能够作不少,例如把 loading 状态提高到 Store 的顶部,那整个站点就只有一个 loading 了,而后你还能够将 fetch 再封装一个 HOC 修改 loading 状态,这就是一个相对完美的 loading,其实 React 业务开发均可以用这个套路。
上面 redux 的例子是否是过于复杂
对于简单的业务,虽然有不少页面,嵌套层次也很复杂,你固然能够不用状态管理工具,你能够试着使用 Context,它能够方便你传递数据,它其实就是 Render Props 的一种实现。
export default React.createContext({ loading: false, changeLoading: () => {} });
写到这,静一下,是否是哪里作错了什么?
个人业务只是想写个简单的 loading 效果,却了解了一堆组件生命周期的概念。
Hooks 恰好帮你解决了这样的问题,Hooks 能容许你经过执行单个函数调用来使用函数中的 React 功能,让你把面向生命周期编程
变成面向业务逻辑编程
。
import React, { useState, useEffect } from "react"; import Loading from "./Loading/index"; import fetch from "./fetch"; function App() { const [loading, setLoading] = useState(true); useEffect(() => { fetch().then(() => { setLoading(false); }); }, []); return <Loading loading={loading} />; } export default App;
上面对每一个点都作了具体实现,但他们都不是隔离的,你能够根据你的认知和业务特色总结抽象一套本身的方法论;
多了解
、多抽象
、多思考
,练就十八般武艺,遇到问题的时候才能游刃有余;
React 如今宣传的东西愈来愈多,你最好先深刻了解他们,而后用批判的眼光,保持理智,防止本身天天用很新的特性重构你本身的代码。
When do I know I’m ready for Redux?
文章可随意转载,但请保留此 原文连接。很是欢迎有激情的你加入 ES2049 Studio,简历请发送至 caijun.hcj(at)alibaba-inc.com 。