安裝react
腳手架並初始化項目html
cnpm install -g create-react-app create-react-app electron-react-today cd electron-react-today npm start
此時項目已經運行在 :localhost:3000
react
electron 7.0.0 實在太坑爹了
使用6.1.2
沒有問題。web
cnpm install --save-dev electron@6.1.2 --verbose
新建main.js
npm
// 引入electron並建立一個Browserwindow const { app, BrowserWindow } = require('electron') const path = require('path') const url = require('url') // 保持window對象的全局引用,避免JavaScript對象被垃圾回收時,窗口被自動關閉. let mainWindow function createWindow () { //建立瀏覽器窗口,寬高自定義具體大小你開心就好 mainWindow = new BrowserWindow({width: 800, height: 600}) /* * 加載應用----- electron-quick-start中默認的加載入口 mainWindow.loadURL(url.format({ pathname: path.join(__dirname, 'index.html'), protocol: 'file:', slashes: true })) */ // 加載應用----適用於 react 項目 mainWindow.loadURL('http://localhost:3000/') // 加載本地html // mainWindow.loadFile('./index.html') // 打開開發者工具,默認不打開 mainWindow.webContents.openDevTools() // 關閉window時觸發下列事件. mainWindow.on('closed', function () { mainWindow = null }) } // 當 Electron 完成初始化並準備建立瀏覽器窗口時調用此方法 app.on('ready', createWindow) // 全部窗口關閉時退出應用. app.on('window-all-closed', function () { // macOS中除非用戶按下 `Cmd + Q` 顯式退出,不然應用與菜單欄始終處於活動狀態. if (process.platform !== 'darwin') { app.quit() } }) app.on('activate', function () { // macOS中點擊Dock圖標時沒有已打開的其他應用窗口時,則一般在應用中重建一個窗口 if (mainWindow === null) { createWindow() } })
在package.json
文件中添加:json
{ "main": "main.js", "scripts": { "electron-start": "electron ." }, }
而後執行:數組
npm run electron-start
看到以下頁面,終於第一步完成了。瀏覽器
useState聲明狀態變量性能優化
const [ count , setCount ] = useState(0);
useEffect代替經常使用生命週期函數bash
// 第一次渲染和每次更新都會被執行 而且是異步執行的 useEffect(()=>{ console.log(`useEffect=>You clicked ${count} times`) }) // 當傳空數組[]時,就是當組件將被銷燬時才進行解綁, // 這也就實現了componentWillUnmount的生命週期函數 useEffect(()=>{ console.log('useEffect=>老弟你來了!Index頁面') return ()=>{ console.log('老弟,你走了!Index頁面') } },[])
useContext 實現數據共享(父子組件傳值)app
能夠經過這個hook
傳遞useReducer
產生的dispatch
函數。
也就是不直接傳遞數據,而是傳遞修改數據的方法,在根組件中經過reducer
修改狀態。
父組件
import React, { useState, createContext } from 'react'; import { Button } from '@material-ui/core'; // 引入子組件 import Num from './Num'; // 建立上下文對象 const CounterContext = createContext(); export default function Counter() { const [count, setCount] = useState(0); return ( <div> <p>點擊了 {count} 次</p> <Button variant="contained" color="primary" onClick={() => setCount(count + 1)} > 點我加一 </Button> <CounterContext.Provider value={count}> <Num /> </CounterContext.Provider> </div> ); } // 導出上下文對象 export { CounterContext };
子組件
import React, { useContext } from 'react'; // 引入父組件的上下文 import { CounterContext } from './Counter'; export default function Count() { const count = useContext(CounterContext); return <h2>{count}</h2> }
useReducer 實現對複雜狀態對象的管理
使用場景
對某個state有不少種操做
子組件須要修改上層組件的值,能夠傳遞一個dispatch函數
const reducer = (state, action) => { switch(action.type) { case: "xx": .... } } const [state, dispatch] = useReducer(/*reducer函數*/ reducer, /*初始值*/ initialVal); dispatch({ type: 'xx', val: '' });
固然還有其餘的Hooks,例如用於性能優化的useMemo
就不說了。
有了以上內容就能夠開發一個簡單的TODoList
應用了。
使用到的內容:material-ui
和 上文中的React Hooks 。
至於如何安裝組件庫能夠自行查看:https://material-ui.com/zh/ge...
總體目錄結構以下圖:
App.js 文件: 承載狀態數據和組件。
import React, { useReducer, createContext } from 'react'; import { initialTodos, filterReducer, todosReducer } from './reducer/index'; import Filter from './components/Filter'; import AddTodo from './components/AddTodo'; import TodoList from './components/TodoList'; // 導出共享對象 export const AppContext = createContext(); function App() { const [todos, dispatchTodos] = useReducer(todosReducer, initialTodos); const [filterVal, dispatchFilter] = useReducer(filterReducer, 'ALL'); return ( <div style={{ margin: '20px 30px 0', maxWidth: 450 }}> <AppContext.Provider value={dispatchTodos}> <AddTodo /> <Filter dispatch={dispatchFilter} /> <TodoList filterVal={filterVal} todos={todos} /> </AppContext.Provider> </div> ); } export default App;
/reducer/index.js 文件: 完成對數據的修改。
import uuid from 'uuid'; export const initialTodos = [ { id: uuid(), label: '學習React Hooks', complete: false, }, { id: uuid(), label: '吃飯睡覺', complete: true, } ]; export const filterReducer = (state, action) => { switch (action.type) { case 'SHOW_ALL': return 'ALL'; case 'SHOW_COMPLETE': return 'COMPLETE'; case 'SHOW_INCOMPLETE': return 'INCOMPLETE'; default: throw Error(); } } export const todosReducer = (state, action) => { switch (action.type) { case 'CHECK_TODO': return state.map(todo => { if (todo.id === action.id) { todo.complete = !todo.complete } return todo; }); case 'DELETE_TODO': console.log(state, action.id) return state.filter(todo => todo.id !== action.id); case 'ADD_TODO': return state.concat(action.todo); default: throw Error(); } }
/components/AddTodo.js: 輸入框,添加任務。
import React, { useState, useContext } from 'react'; import { Input, Button } from '@material-ui/core'; import uuid from 'uuid'; import { AppContext } from '../App'; export default function AddTodo() { const dispatch = useContext(AppContext); const handleSubmit = () => { if (!task) return; setTask(''); dispatch({ type: 'ADD_TODO', todo: { id: uuid(), label: task, complete: false } }); } const [task, setTask] = useState(''); return ( <div style={{ display: 'flex' }}> <Input value={task} style={{ flex: 1 }} onChange={(e) => setTask(e.target.value)} inputProps={{ 'aria-label': 'description' }} /> <Button color="primary" onClick={handleSubmit}>添加</Button> </div> ) }
/components/Filter.js: 篩選任務。
import React from 'react'; import { Button } from '@material-ui/core'; export default function Filter({ dispatch }) { return ( <div style={{ display: 'flex', justifyContent: 'space-between', margin: '20px 0' }}> <Button color="primary" onClick={() => dispatch({ type: 'SHOW_ALL' })}>所有</Button> <Button color="primary" onClick={() => dispatch({ type: 'SHOW_COMPLETE' })}>已完成</Button> <Button color="primary" onClick={() => dispatch({ type: 'SHOW_INCOMPLETE' })}>未完成</Button> </div> ) }
/components/TodoList.js: 展現全部的任務。
import React, { useContext } from 'react'; import { List, ListItem, ListItemText, ListItemSecondaryAction, IconButton, Checkbox, ListItemIcon } from '@material-ui/core'; import { Delete as DeleteIcon } from '@material-ui/icons'; import { AppContext } from '../App' export default function TodoList({ todos, filterVal }) { const dispatch = useContext(AppContext); const deleteTodo = (item) => { dispatch({ type: 'DELETE_TODO', id: item.id }); } const checkTodo = (item) => { dispatch({ type: 'CHECK_TODO', id: item.id }); } // 過濾 todos const filteredTodos = () => { if (filterVal === 'ALL') return todos; if (filterVal === 'COMPLETE') { return todos.filter(todo => todo.complete); } if (filterVal === 'INCOMPLETE') { return todos.filter(todo => !todo.complete); } return []; } return ( <List component="nav" aria-label="secondary mailbox folders"> { filteredTodos().map(item => ( <ListItem key={item.id} button> <ListItemIcon> <Checkbox edge="start" checked={item.complete} onChange={() => checkTodo(item)} disableRipple /> </ListItemIcon> <ListItemText primary={item.label} /> <ListItemSecondaryAction> <IconButton onClick={() => deleteTodo(item)} edge="end" aria-label="delete"> <DeleteIcon /> </IconButton> </ListItemSecondaryAction> </ListItem> )) } </List> ) }
至此,一個簡單的ToDoList
就完成了。