{"id":159108,"date":"2019-10-06T11:00:04","date_gmt":"2019-10-06T03:00:04","guid":{"rendered":"https:\/\/lrxjmw.cn\/?p=159108"},"modified":"2019-09-24T09:56:22","modified_gmt":"2019-09-24T01:56:22","slug":"react-mirror","status":"publish","type":"post","link":"https:\/\/lrxjmw.cn\/react-mirror.html","title":{"rendered":"React \u65b0\u6846\u67b6\uff1aMirror"},"content":{"rendered":"\n\n\n
\u5bfc\u8bfb<\/td>\nMirror \u662f\u4e00\u6b3e\u57fa\u4e8e React\u3001Redux \u548c react-router \u7684\u524d\u7aef\u6846\u67b6\uff0c\u7b80\u6d01\u9ad8\u6548\u3001\u7075\u6d3b\u53ef\u9760\u3002<\/strong><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n
\u4e3a\u4ec0\u4e48\uff1f<\/strong><\/span><\/div>\n

\u6211\u4eec\u70ed\u7231 React \u548c Redux\u3002\u4f46\u662f\uff0cRedux \u4e2d\u6709\u592a\u591a\u7684\u6837\u677f\u6587\u4ef6\uff0c\u9700\u8981\u5f88\u591a\u7684\u91cd\u590d\u52b3\u52a8\uff0c\u8fd9\u4e00\u70b9\u4ee4\u4eba\u6cae\u4e27\uff1b\u66f4\u522b\u63d0\u5728\u5b9e\u9645\u7684 React \u5e94\u7528\u4e2d\uff0c\u8fd8\u8981\u96c6\u6210 react-router \u7684\u8def\u7531\u4e86\u3002<\/p>\n

\u4e00\u4e2a\u5178\u578b\u7684 React\/Redux \u5e94\u7528\u770b\u8d77\u6765\u50cf\u4e0b\u9762\u8fd9\u6837\uff1a<\/p>\n

\r\nactions.js\r\nexport const ADD_TODO = 'todos\/add'export const COMPLETE_TODO = 'todos\/complete'export function addTodo(text) {  return {    type: ADD_TODO,\r\n    text\r\n  }\r\n}export function completeTodo(id) {  return {    type: COMPLETE_TODO,\r\n    id\r\n  }\r\n}\r\n<\/pre>\n
\r\nreducers.js\r\nimport { ADD_TODO, COMPLETE_TODO } from '.\/actions'let nextId = 0export default function todos(state = [], action) {  switch (action.type) {    case ADD_TODO:      return [...state, {text: action.text, id: nextId++}]    case COMPLETE_TODO:      return state.map(todo => {        if (todo.id === action.id) todo.completed = true\r\n        return todo\r\n      })    default:      return state\r\n  }\r\n}\r\n<\/pre>\n
\r\nTodos.js\r\nimport { addTodo, completeTodo } from '.\/actions'\/\/ ...\/\/ \u5728\u67d0\u4e2a\u4e8b\u4ef6\u5904\u7406\u51fd\u6570\u4e2ddispatch(addTodo('a new todo'))\/\/ \u5728\u53e6\u4e00\u4e2a\u4e8b\u4ef6\u5904\u7406\u51fd\u6570\u4e2ddispatch(completeTodo(42))\r\n<\/pre>\n

\u770b\u8d77\u6765\u662f\u4e0d\u662f\u6709\u70b9\u7e41\u5197\uff1f\u8fd9\u8fd8\u662f\u6ca1\u8003\u8651 \u5f02\u6b65 action \u7684\u60c5\u51b5\u5462\u3002\u5982\u679c\u8981\u5904\u7406\u5f02\u6b65 action\uff0c\u8fd8\u9700\u8981\u5f15\u5165 middleware\uff08\u6bd4\u5982 redux-thunk \u6216\u8005 redux-saga\uff09\uff0c\u90a3\u4e48\u4ee3\u7801\u5c31\u66f4\u7e41\u7410\u4e86\u3002<\/p>\n

\u4f7f\u7528 Mirror \u91cd\u5199<\/strong><\/span><\/div>\n
\r\nTodos.js\r\nimport mirror, { actions } from 'mirrorx'let nextId = 0mirror.model({  name: 'todos',  initialState: [],  reducers: {\r\n    add(state, text) {      return [...state, {text, id: nextId++}]\r\n    },\r\n    complete(state, id) {      return state.map(todo => {        if (todo.id === id) todo.completed = true\r\n        return todo\r\n      })\r\n    }\r\n  }\r\n})\/\/ ...\/\/ \u5728\u67d0\u4e2a\u4e8b\u4ef6\u5904\u7406\u51fd\u6570\u4e2dactions.todos.add('a new todo')\/\/ \u5728\u53e6\u4e00\u4e2a\u4e8b\u4ef6\u5904\u7406\u51fd\u6570\u4e2dactions.todos.complete(42)\r\n<\/pre>\n

\u662f\u4e0d\u662f\u5c31\u7b80\u5355\u5f88\u591a\u4e86\uff1f\u53ea\u9700\u4e00\u4e2a\u65b9\u6cd5\uff0c\u5373\u53ef\u5b9a\u4e49\u6240\u6709\u7684 action \u548c reducer\uff08\u4ee5\u53ca \u5f02\u6b65 action\uff09\u3002<\/p>\n

\u800c\u4e14\uff0c\u8fd9\u884c\u4ee3\u7801\uff1a<\/p>\n

\r\nactions.todos.add('a new todo')\r\n<\/pre>\n

\u5b8c\u5168\u7b49\u540c\u4e8e\u8fd9\u884c\u4ee3\u7801\uff1a<\/p>\n

\r\ndispatch({  type: 'todos\/add',  text: 'a new todo'})\r\n<\/pre>\n

\u5b8c\u5168\u4e0d\u7528\u5173\u5fc3\u5177\u4f53\u7684 action type\uff0c\u4e0d\u7528\u5199\u5927\u91cf\u7684\u91cd\u590d\u4ee3\u7801\u3002\u7b80\u6d01\uff0c\u9ad8\u6548\u3002<\/p>\n

\u5f02\u6b65 action<\/strong><\/span><\/div>\n

\u4e0a\u8ff0\u4ee3\u7801\u793a\u4f8b\u4ec5\u4ec5\u9488\u5bf9\u540c\u6b65 action\u3002<\/p>\n

\u4e8b\u5b9e\u4e0a\uff0cMirror \u5bf9\u5f02\u6b65 action \u7684\u5904\u7406\uff0c\u4e5f\u540c\u6837\u7b80\u5355\uff1a<\/p>\n

\r\nmirror.model({  \/\/ \u7701\u7565\u524d\u8ff0\u4ee3\u7801\r\n  effects: {    async addAsync(data, getState) {      const res = await Promise.resolve(data)      \/\/ \u8c03\u7528 `actions` \u4e0a\u7684\u65b9\u6cd5 dispatch \u4e00\u4e2a\u540c\u6b65 action\r\n      actions.todos.add(res)\r\n    }\r\n  }\r\n})\r\n<\/pre>\n

\u6ca1\u9519\uff0c\u8fd9\u6837\u5c31\u5b9a\u4e49\u4e86\u4e00\u4e2a\u5f02\u6b65 action\u3002\u4e0a\u8ff0\u4ee3\u7801\u7684\u6548\u679c\u7b49\u540c\u4e8e\u5982\u4e0b\u4ee3\u7801\uff1a<\/p>\n

\r\nactions.todos.addSync = (data, getState) => {  return dispatch({    type: 'todos\/addAsync',\r\n    data\r\n  })\r\n}\r\n<\/pre>\n

\u8c03\u7528 actions.todos.addSync \u65b9\u6cd5\uff0c\u5219\u4f1a dispatch \u4e00\u4e2a type \u4e3a todos\/addAsync \u7684 action\u3002<\/p>\n

\u4f60\u53ef\u80fd\u6ce8\u610f\u5230\u4e86\uff0c\u5904\u7406\u8fd9\u6837\u7684 action\uff0c\u5fc5\u987b\u8981\u501f\u52a9\u4e8e middleware\u3002\u4e0d\u8fc7\u4f60\u5b8c\u5168\u4e0d\u7528\u62c5\u5fc3\uff0c\u4f7f\u7528 Mirror \u65e0\u987b\u5f15\u5165\u989d\u5916\u7684 middleware\uff0c\u4f60\u53ea\u7ba1\u5b9a\u4e49 action\/reducer\uff0c\u7136\u540e\u7b80\u5355\u5730\u8c03\u7528\u4e00\u4e2a\u51fd\u6570\u5c31\u884c\u4e86\u3002<\/p>\n

\u66f4\u7b80\u5355\u7684\u8def\u7531<\/strong><\/span><\/div>\n

Mirror \u5b8c\u5168\u6309\u7167 react-router 4.x \u7684\u63a5\u53e3\u548c\u65b9\u5f0f\u5b9a\u4e49\u8def\u7531\uff0c\u56e0\u6b64\u6ca1\u6709\u4efb\u4f55\u65b0\u7684\u5b66\u4e60\u6210\u672c\u3002<\/p>\n

\u66f4\u65b9\u4fbf\u7684\u662f\uff0cMirror \u7684 Router \u7ec4\u4ef6\uff0c\u5176 history \u5bf9\u8c61\u4ee5\u53ca\u8ddf Redux store \u7684\u8054\u7ed3\u662f\u81ea\u52a8\u5904\u7406\u8fc7\u7684\uff0c\u6240\u4ee5\u4f60\u5b8c\u5168\u4e0d\u7528\u5173\u5fc3\u5b83\u4eec\uff0c\u53ea\u9700\u5173\u5fc3\u4f60\u81ea\u5df1\u7684\u5404\u4e2a\u8def\u7531\u5373\u53ef\u3002<\/p>\n

\u800c\u4e14\uff0c\u624b\u52a8\u66f4\u65b0\u8def\u7531\u4e5f\u975e\u5e38\u7b80\u5355\uff0c\u8c03\u7528 actions.routing \u5bf9\u8c61\u4e0a\u7684\u65b9\u6cd5\u5373\u53ef\u66f4\u65b0\u3002<\/p>\n

\u7406\u5ff5<\/strong><\/span><\/div>\n

Mirror \u7684\u8bbe\u8ba1\u7406\u5ff5\u662f\uff0c\u5728\u5c3d\u53ef\u80fd\u5730\u907f\u514d\u53d1\u660e\u65b0\u7684\u6982\u5ff5\uff0c\u5e76\u4fdd\u6301\u73b0\u6709\u5f00\u53d1\u6a21\u5f0f\u7684\u524d\u63d0\u4e0b\uff0c\u51cf\u5c11\u91cd\u590d\u52b3\u52a8\uff0c\u63d0\u9ad8\u5f00\u53d1\u6548\u7387\u3002<\/p>\n

Mirror \u603b\u5171\u53ea\u63d0\u4f9b\u4e86 4 \u4e2a\u65b0\u7684 API\uff0c\u5176\u4f59\u4ec5\u6709\u7684\u51e0\u4e2a\u4e5f\u90fd\u662f\u5df2\u5b58\u5728\u4e8e React\/Redux\/react-router \u7684\u63a5\u53e3\uff0c\u53ea\u4e0d\u8fc7\u505a\u4e86\u5c01\u88c5\u548c\u5f3a\u5316\u3002<\/p>\n

\u6240\u4ee5\uff0cMirror \u5e76\u6ca1\u6709\u201c\u98a0\u8986\u201d React\/Redux \u5f00\u53d1\u6d41\uff0c\u53ea\u662f\u7b80\u5316\u4e86\u63a5\u53e3\u8c03\u7528\uff0c\u7701\u53bb\u4e86\u6837\u677f\u4ee3\u7801\uff1a<\/p>\n

\u5728\u5bf9\u8def\u7531\u7684\u5904\u7406\u4e0a\uff0c\u4e5f\u662f\u5982\u6b64\u3002<\/p>\n

\u5982\u4f55\u4f7f\u7528\uff1f<\/strong><\/span><\/div>\n

\u4f7f\u7528 create-react-app \u521b\u5efa\u4e00\u4e2a\u65b0\u7684 app\uff1a<\/p>\n

\r\n$ npm i -g create-react-app\r\n$ create-react-app my-app\r\n<\/pre>\n

\u521b\u5efa\u4e4b\u540e\uff0c\u4ece npm \u5b89\u88c5 Mirror\uff1a<\/p>\n

\r\n$ cd my-app\r\n$ npm i --save mirrorx\r\n$ npm start\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"

\u6211\u4eec\u70ed\u7231 React \u548c Redux\u3002\u4f46\u662f\uff0cRedux \u4e2d\u6709\u592a\u591a\u7684\u6837\u677f\u6587\u4ef6\uff0c\u9700\u8981\u5f88\u591a\u7684\u91cd\u590d\u52b3\u52a8\uff0c\u8fd9\u4e00\u70b9\u4ee4\u4eba\u6cae\u4e27 […]<\/p>\n","protected":false},"author":1479,"featured_media":119570,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[55],"tags":[],"class_list":["post-159108","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-thread"],"acf":[],"_links":{"self":[{"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/posts\/159108","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/users\/1479"}],"replies":[{"embeddable":true,"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/comments?post=159108"}],"version-history":[{"count":4,"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/posts\/159108\/revisions"}],"predecessor-version":[{"id":159261,"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/posts\/159108\/revisions\/159261"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/media\/119570"}],"wp:attachment":[{"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/media?parent=159108"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/categories?post=159108"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/tags?post=159108"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}