Redux Toolkit linting 悖论
Redux Toolkit linting paradox
我在文件 searchSlice.js
中定义了一个 Redux Toolkit 切片,它负责查询 API 并将响应数据存储在商店的状态中。目前看起来像这样:
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';
const initialState = {
query: '',
status: 'idle',
movies: [],
totalResults: null,
};
// Create slice
export const searchSlice = createSlice({
name: 'search',
initialState,
reducers: {
updateQuery: (state, action) => {
state.query = action.payload;
},
},
extraReducers: (builder) => {
builder
.addCase(getMovies.pending, (state) => {
state.status = 'pending';
})
.addCase(getMovies.fulfilled, (state, action) => {
state.status = 'idle';
state.movies = action.payload.results;
state.totalResults = action.payload.total_results;
});
},
});
// Actions
export const { updateQuery } = searchSlice.actions;
// Reducers
export default searchSlice.reducer;
// Selectors
export const selectQuery = (state) => state.search.query;
export const selectStatus = (state) => state.search.status;
export const selectAllMovies = (state) => state.search.movies;
export const selectTotalResults = (state) => state.search.totalResults;
// Thunks
export const getMovies = createAsyncThunk(
'search/getMovies',
async (payload, store) => {
if (!store.getState().search) {
dispatchEvent(updateQuery(payload));
}
try {
console.log('payload: ', payload);
const res = await axios.get(`/search?query=${store.getState().search}`);
return res.data;
} catch (err) {
return err;
}
}
);
据我所知,除了导出实际的切片对象本身,您还必须导出其必要的和附带的组件:
- 操作
- 减速器
- 选择器
- 帅哥
由于上述组件高度耦合和相互依赖的性质,ESLint 将根据 searchSlice.js
文件中组件的顺序(按行号)抛出不同的 linting 错误。例如,在上面的代码片段中,linting 错误是:
'getMovies' was used before it was defined. eslint(no-use-before-define)
如果我们尝试通过将 getMovies
函数声明重新排列到调用上方来修复错误,如下所示:
// ...
// Thunks
export const getMovies = createAsyncThunk(
'search/getMovies',
async (payload, store) => {
if (!store.getState().search) {
dispatchEvent(updateQuery(payload));
}
try {
console.log('payload: ', payload);
const res = await axios.get(`/search?query=${store.getState().search}`);
return res.data;
} catch (err) {
return err;
}
}
);
// ...
// Create slice
export const searchSlice = createSlice({
name: 'search',
initialState,
reducers: {
updateQuery: (state, action) => {
state.query = action.payload;
},
},
extraReducers: (builder) => {
builder
.addCase(getMovies.pending, (state) => {
state.status = 'pending';
})
.addCase(getMovies.fulfilled, (state, action) => {
state.status = 'idle';
state.movies = action.payload.results;
state.totalResults = action.payload.total_results;
});
},
});
// ...
然后我们得到相同的 linting 错误,但函数定义不同:
'updateQuery' was used before it was defined. eslint(no-use-before-define)
似乎无论文件的排列如何,ESLint 都会抛出一个自相矛盾的 no-use-before-define
错误。
是否有不涉及更改 ESLint 规则的解决方案?有没有更好的方法来构建代码?我已经尝试将它拆分成更小的文件,但由于伴随切片功能的高度相互依赖性,ESLint 将开始抛出 import/no-cycle
错误,因为两个文件都需要从彼此导入内容。
作为一个附加问题,提升如何在这里发挥作用?
当你处理一个循环时,你需要弄清楚哪个是有意义的依赖,哪个是依赖。在这种情况下,从 thunk 中删除 reducer 比从 reducer 中删除 thunk 更容易。
您可以通过从 thunk 中删除额外调度的 updateQuery
操作并在您的 reducer 中处理该逻辑来修复依赖关系。您可以通过 action.meta.arg
属性 从 getMovies.pending
case reducer 中的 thunk 访问(混淆命名的)payload
变量,其中包含您称为 thunk 动作创建者的参数与.
export const getMovies = createAsyncThunk(
'search/getMovies',
async (query) => {
const res = await axios.get(`/search?query=${query}`);
return res.data;
// Don't catch errors here. Let them be thrown and handled by the 'rejected' action.
}
);
export const searchSlice = createSlice({
name: 'search',
initialState,
reducers: {
// you might not even need this anymore, unless you use it elsewhere.
updateQuery: (state, action) => {
state.query = action.payload;
},
},
extraReducers: (builder) => {
builder
.addCase(getMovies.pending, (state, action) => {
// Update the query property of the state.
state.query = action.meta.arg;
state.status = 'pending';
})
.addCase(getMovies.fulfilled, (state, action) => {
state.status = 'idle';
state.movies = action.payload.results;
state.totalResults = action.payload.total_results;
});
},
});
顺便说一下,条件 if (!store.getState().search)
没有意义。那将检查整个切片是否真实,它总是真实的。
我在文件 searchSlice.js
中定义了一个 Redux Toolkit 切片,它负责查询 API 并将响应数据存储在商店的状态中。目前看起来像这样:
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';
const initialState = {
query: '',
status: 'idle',
movies: [],
totalResults: null,
};
// Create slice
export const searchSlice = createSlice({
name: 'search',
initialState,
reducers: {
updateQuery: (state, action) => {
state.query = action.payload;
},
},
extraReducers: (builder) => {
builder
.addCase(getMovies.pending, (state) => {
state.status = 'pending';
})
.addCase(getMovies.fulfilled, (state, action) => {
state.status = 'idle';
state.movies = action.payload.results;
state.totalResults = action.payload.total_results;
});
},
});
// Actions
export const { updateQuery } = searchSlice.actions;
// Reducers
export default searchSlice.reducer;
// Selectors
export const selectQuery = (state) => state.search.query;
export const selectStatus = (state) => state.search.status;
export const selectAllMovies = (state) => state.search.movies;
export const selectTotalResults = (state) => state.search.totalResults;
// Thunks
export const getMovies = createAsyncThunk(
'search/getMovies',
async (payload, store) => {
if (!store.getState().search) {
dispatchEvent(updateQuery(payload));
}
try {
console.log('payload: ', payload);
const res = await axios.get(`/search?query=${store.getState().search}`);
return res.data;
} catch (err) {
return err;
}
}
);
据我所知,除了导出实际的切片对象本身,您还必须导出其必要的和附带的组件:
- 操作
- 减速器
- 选择器
- 帅哥
由于上述组件高度耦合和相互依赖的性质,ESLint 将根据 searchSlice.js
文件中组件的顺序(按行号)抛出不同的 linting 错误。例如,在上面的代码片段中,linting 错误是:
'getMovies' was used before it was defined. eslint(no-use-before-define)
如果我们尝试通过将 getMovies
函数声明重新排列到调用上方来修复错误,如下所示:
// ...
// Thunks
export const getMovies = createAsyncThunk(
'search/getMovies',
async (payload, store) => {
if (!store.getState().search) {
dispatchEvent(updateQuery(payload));
}
try {
console.log('payload: ', payload);
const res = await axios.get(`/search?query=${store.getState().search}`);
return res.data;
} catch (err) {
return err;
}
}
);
// ...
// Create slice
export const searchSlice = createSlice({
name: 'search',
initialState,
reducers: {
updateQuery: (state, action) => {
state.query = action.payload;
},
},
extraReducers: (builder) => {
builder
.addCase(getMovies.pending, (state) => {
state.status = 'pending';
})
.addCase(getMovies.fulfilled, (state, action) => {
state.status = 'idle';
state.movies = action.payload.results;
state.totalResults = action.payload.total_results;
});
},
});
// ...
然后我们得到相同的 linting 错误,但函数定义不同:
'updateQuery' was used before it was defined. eslint(no-use-before-define)
似乎无论文件的排列如何,ESLint 都会抛出一个自相矛盾的 no-use-before-define
错误。
是否有不涉及更改 ESLint 规则的解决方案?有没有更好的方法来构建代码?我已经尝试将它拆分成更小的文件,但由于伴随切片功能的高度相互依赖性,ESLint 将开始抛出 import/no-cycle
错误,因为两个文件都需要从彼此导入内容。
作为一个附加问题,提升如何在这里发挥作用?
当你处理一个循环时,你需要弄清楚哪个是有意义的依赖,哪个是依赖。在这种情况下,从 thunk 中删除 reducer 比从 reducer 中删除 thunk 更容易。
您可以通过从 thunk 中删除额外调度的 updateQuery
操作并在您的 reducer 中处理该逻辑来修复依赖关系。您可以通过 action.meta.arg
属性 从 getMovies.pending
case reducer 中的 thunk 访问(混淆命名的)payload
变量,其中包含您称为 thunk 动作创建者的参数与.
export const getMovies = createAsyncThunk(
'search/getMovies',
async (query) => {
const res = await axios.get(`/search?query=${query}`);
return res.data;
// Don't catch errors here. Let them be thrown and handled by the 'rejected' action.
}
);
export const searchSlice = createSlice({
name: 'search',
initialState,
reducers: {
// you might not even need this anymore, unless you use it elsewhere.
updateQuery: (state, action) => {
state.query = action.payload;
},
},
extraReducers: (builder) => {
builder
.addCase(getMovies.pending, (state, action) => {
// Update the query property of the state.
state.query = action.meta.arg;
state.status = 'pending';
})
.addCase(getMovies.fulfilled, (state, action) => {
state.status = 'idle';
state.movies = action.payload.results;
state.totalResults = action.payload.total_results;
});
},
});
顺便说一下,条件 if (!store.getState().search)
没有意义。那将检查整个切片是否真实,它总是真实的。