安装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
就完成了。