1. React Component父子组件间传值
1.1 Parent to Child — Use Prop
class App extends React.Component {
render() {
[... somewhere in here I define a variable listName which I think will be useful as data in my ToDoList component...]
return (
<div>
<InputBar/>
<ToDoList listNameFromParent={listName}/>
</div>
);
}
}
现在在ToDoList这个component中,使用this.props.listNameFromParent即可拿到listName
1.2 Child to Parent — Use a callback and states
- Define a callback in my parent which takes the data I need in as a parameter.
- Pass that callback as a prop to the child (see above).
- Call the callback using this.props.[callback] in the child, and pass in the data as the argument.
// parent
class ToDoList extends React.Component {
constructor(props) {
super(props);
this.state = {
listDataFromChild: null
};
};
myCallback = (dataFromChild) => {
this.setState({ listDataFromChild: dataFromChild });
[...we will use the dataFromChild here...]
};
render() {
return (
<div>
<ToDoItem callbackFromParent={this.myCallback}/>
</div>
);
}
}
// child
class ToDoItem extends React.Component{
someFn = () => {
[...somewhere in here I define a variable listInfo which I think will be useful as data in my ToDoList component...]
this.props.callbackFromParent(listInfo);
},
render() {
[...]
}
};
ToDoList (parent) will now be able to use listInfo within it’s myCallback function!
1.3 Between Siblings — Combine the above
Not surprisingly, to pass data between siblings, you have to use the parent as an intermediary.
2. Redux Reducer
2.1 更新state
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
visibilityFilter: action.filter
})
default:
return state
}
}
We don’t mutate the state. We create a copy with Object.assign(). Object.assign(state, { visibilityFilter: action.filter }) is also wrong: it will mutate the first argument. You must supply an empty object as the first parameter. You can also enable the object spread operator proposal to write { …state, …newState } instead:
An alternative approach is to use the object spread syntax recently added to the JavaScript specification:
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return { ...state, visibilityFilter: action.filter }
default:
return state
}
}
2.2 Updating Nested Objects
2.2.1 updating state.first.second[someId].fourth might look like:
function updateVeryNestedField(state, action) {
return {
...state,
first: {
...state.first,
second: {
...state.first.second,
[action.someId]: {
...state.first.second[action.someId],
fourth: action.someValue
}
}
}
}
}
看起来很复杂,所以:This is one of several reasons why you are encouraged to keep your state flattened, and compose reducers as much as possible.
2.2.2 Common Mistake #1: New variables that point to the same objects
Defining a new variable does not create a new actual object - it only creates another reference to the same object. An example of this error would be:
function updateNestedState(state, action) {
let nestedState = state.nestedState
// ERROR: this directly modifies the existing object reference - don't do this!
nestedState.nestedField = action.data
return {
...state,
nestedState
}
}
This function does correctly return a shallow copy of the top-level state object, but because the nestedState variable was still pointing at the existing object, the state was directly mutated.
2.2.3 Common Mistake #2: Only making a shallow copy of one level
Another common version of this error looks like this:
function updateNestedState(state, action) {
// Problem: this only does a shallow copy!
let newState = { ...state }
// ERROR: nestedState is still the same object!
newState.nestedState.nestedField = action.data
return newState
}
Doing a shallow copy of the top level is not sufficient - the nestedState object should be copied as well. 应该newState.nestedState就还是state.nestedState
3. react state vs redux state
- React state is stored locally within a component. When it needs to be shared with other components, it is passed down through props.
用法: react component中,自己定义一个this.state,或者在hook function component中,用useState,得到的是react state
- When using Redux, state is stored globally in the Redux store. Any component that needs access to a value may subscribe to the store and gain access to that value.
用法:比如useSelector
4. Kendo - React中好看又简单的component库
4.1 input
4.2 dropdownlist
4.3 几点注意:
-
按要求下载一系列依赖包,否则可能会有各种dependency找不到的问题:
npm install --save @progress/kendo-react-grid @progress/kendo-data-query @progress/kendo-react-inputs @progress/kendo-react-intl @progress/kendo-react-dropdowns @progress/kendo-react-dateinputs @progress/kendo-drawing @progress/kendo-react-data-tools
有的的确用不到可以试着不下载或者从package.json里删了 -
- Default theme—Available through the @progress/kendo-theme-default NPM module.
- Bootstrap theme—Available through the @progress/kendo-theme-bootstrap NPM module.
- Material theme—Available through the @progress/kendo-theme-material NPM module.
我只用到了1和3,如果加上2一些效果反而被bootstrap效果覆盖了:
npm install --save @progress/kendo-theme-default
npm install --save @progress/kendo-theme-material
而且这里引入css比scss好,因为css是已经编译好的
import '@progress/kendo-theme-default/dist/all.css'; import '@progress/kendo-theme-material/dist/all.css';
-
本来一直在找input的onChange,基本找不到,基本都是onSubmit,但是试了试onChange也能用在kendo的floating label input上,只是后来想想,onChange的确不好,每次打一个字母,就会make一个新的request…但最后还是用了onChange…
而且之前把onChange写成了onchange导致每次都是undefined的值传入…傻了
5. Every time react state changes, react component render will re-run
6. React display pretty json / React显示json的几个包
6.1 react-json-view
觉得这个最好,还能折叠
npm install --save react-json-view
6.2 react-json-pretty
npm install --save react-json-pretty
6.3 关于使用方法,和可能遇到的几个问题,见我另一篇博客
7. BroswerRouter vs ConnectedRouter
import { ConnectedRouter } from 'connected-react-router/immutable';
import { BrowserRouter as Router,} from 'react-router-dom';
Answer 1: ConnectedRouter is to be used with Redux and can synchronize router state with a Redux store.
BrowserRouter is the ‘standard’ React router for the browser, to keep the UI in sync with the current URL.
Answer 2: The main difference in connected-react-router/immutable in is that history is stored in redux as immutable object so you can time travel your history any time in the redux-life of the application.
所以我用了ConnectedRouter,不过没有试其他的可不可以
https://redux.js.org/advanced/usage-with-react-router
8. React router: exact path vs path
url redirect but new component not rendered in that page, still the old component: path -> exact path:之前遇到一个问题,就是react router中点击别的组件,发现url更新了,但是页面并没有更新,原因就是没有写成exact path,如果只是path,就会返回第一个匹配的url的component
<Route path="/users" component={Users} />
<Route path="/users/create" component={CreateUser} />
Now the problem here, when we go to http://app.com/users the router will go through all of our defined routes and return the FIRST match it finds. So in this case, it would find the Users route first and then return it. All good.
But, if we went to http://app.com/users/create, it would again go through all of our defined routes and return the FIRST match it finds. React router does partial matching, so /users partially matches /users/create, so it would incorrectly return the Users route again!
The exact param disables the partial matching for a route and makes sure that it only returns the route if the path is an EXACT match to the current url.
So in this case, we should add exact to our Users route so that it will only match on /users:
<Route exact path="/users" component={Users} />
<Route path="/users/create" component={CreateUser} />
Using exact path may throw error: Value must be set for boolean attributes.
Solved by:
You just need to add this to your tslint.json to suppress it: "jsx-boolean-value": false
8. How to combine a UI with a backend
9. npm ERR! code ELIFECYCLE
-
Step 1: $ npm cache clean --force
-
Step 2: Delete node_modules by $ rm -rf node_modules package-lock.json folder, or delete it manually by going into the directory and right-click > delete / move to trash. Also, delete package-lock.json file too.
-
Step 3: npm install
-
To start again, $ npm start (This step I didn’t use I remember)
10. React-state: useState
…
10.1
It is important to keep this in mind because, for example, if you want to update the state based on the new properties the component receives:
const Message= (props) => {
const messageState = useState( props.message );
/* ... */
}
10.2
Using useState alone won’t work because its argument is used the first time only — not every time the property changes (look here for the right way to do this).:
You must make use of useEffect hooks to implement, e.g.:
export const Persons = (props) => {
const [nameState , setNameState] = useState(props)
useEffect(() => {
setNameState(props);
}, [props])
return (...)
}
useState doesn’t return just a variable as the previous examples imply.
It returns an array, where the first element is the state variable and the second element is a function to update the value of the variable:
const Message= () => {
const [message, setMessage]= useState( '' );
}
This way, you can use the state variable in the functional component like any other variable:
const Message = () => {
const [message, setMessage] = useState( '' );
return (
<div>
<input
type="text"
value={message}
placeholder="Enter a message"
onChange={e => setMessage(e.target.value)}
/>
<p>
<strong>{message}</strong>
</p>
</div>
);
};
11. Jest: get started
大约有两种方法,一种是写一个jest.config.js
,一种是在package.json
里写明‘jest’
配置。
IntelliJ run的时候,会先找jest.config.js
,没找到会继续找package.json
里的‘jest’
,如果还没找到就会用Jest里default的config。
我用的是package.json
What is Jasmine?
DOM-less simple JavaScript testing framework. Jasmine is a Behavior Driven Development testing framework for JavaScript. It does not rely on browsers, DOM, or any JavaScript framework. Thus it’s suited for websites, Node.js projects, or anywhere that JavaScript can run.
What is Jest?
Painless JavaScript Unit Testing. Jest provides you with multiple layers on top of Jasmine.
12. karma
这一块我查了,但实际还没有用到
https://stackoverflow.com/questions/47329520/unit-testing-react-using-karma-and-jasmine
https://www.codementor.io/@kimagure/testing-reactjs-components-with-karma-and-webpack-8sdzi6hkf
13. 如果npm install不指明dev,会install devDependencies还是dependencies?
首先,如果package json里有,那么那个包写在哪(devDependencies / dependencies),自然就会下载到哪
如果package json里没有,那么下载的时候必须 -save然后指明在哪,就会自动地把这个包添加到devDependencies或者dependencies。
如果package json里没有,下载的时候也不指明… 会下载但是不会加到package.json里。但是需要一个依赖包却不写到package.json这种情况,不太会遇到?
14. IntelliJ里直接run Jest文件
14.1 找不到jest config file
我用的是package.json里的jest,而不是jest.config.js:
Edit Configuration中,work directory应该是有package.json的目录,有的project根目录中的子目录可能才有package.json,这也是导致找不到config的原因
14.2 IntelliJ terminal可以运行jest,但是没法直接run
在package.json的scripts里写上:”test“:"jest"
,然后在IntelliJ terminal run: npm run test
,就可以运行jest测试文件。
但是为什么在Edit Configuration里就总是找不到test文件呢:
No tests found when using jest
后来发现不是什么其它原因,就是那些Edit Configuration很容易写错,后来发现一个简单的方法:
每次Edit Configuration,+Jest后,直接在弹出来的配置框中选择All Test,然后在下方run的console右键那些run过的单个测试,然后点击run,就可以run成功,此时再点击IntelliJ的Edit Configuration,就可以看一下Edit Configuration到底该怎么写了。
而且有些describe里的测试,还是it测试,好像的确没法单个run,有时候还是得一个测试文件一个测试文件(spec.tsx)的为最小粒度地去run。
一些参考文档:
官方文档:
https://www.jetbrains.com/help/idea/running-unit-tests-on-jest.html
https://stackoverflow.com/questions/29904115/running-jest-tests-directly-in-intellij-idea-webstorm
15. cwd是什么
What’s the difference between
console.log(process.cwd())
and
console.log(__dirname);
process.cwd() returns the current working directory,
i.e. the directory from which you invoked the node command.
__dirname returns the directory name of the directory containing the JavaScript source code file
16. Tutorial: 如何用jest和enzyme对react进行测试
17. it vs test
In the docs it says here: it is an alias of test. So they are exactly the same.
test(name, fn, timeout)
// Also under the alias:
it(name, fn, timeout)
// example
describe('rain', () => {
test('did not rain', () => {
expect(inchesOfRain()).toBe(0);
});
it('did not rain', () => {
expect(inchesOfRain()).toBe(0);
});
});