你好,我想要javascript->打字稿!但是,好难..
帮助!
// store.js
import { applyMiddleware, createStore, compose, Store } from "redux";
import createSagaMiddleware, { Task } from "redux-saga";
import { createWrapper } from "next-redux-wrapper";
import { composeWithDevTools } from "redux-devtools-extension";
import reducer from "./reducers";
import rootSaga from "./sagas";
const configureStore = () => {
const sagaMiddleware = createSagaMiddleware();
const middlewares = [sagaMiddleware];
const enhancer =
process.env.NODE_ENV === "production"
? compose(applyMiddleware(...middlewares))
: composeWithDevTools(applyMiddleware(...middlewares));
const store = createStore(reducer, enhancer);
store.sagaTask = sagaMiddleware.run(rootSaga);
return store;
};
const wrapper = createWrapper(configureStore, {
debug: process.env.NODE_ENV === "development",
});
export default wrapper;
// reducers/index.ts
import { HYDRATE } from "next-redux-wrapper";
import { AnyAction, combineReducers } from "redux";
import url, { IUrlReducerState } from "./reducer_url";
import user, { IUserReducerState } from "./reducer_user";
export type State = {
url: IUrlReducerState;
user: IUserReducerState;
};
const rootReducer = (state: State, action: AnyAction) => {
switch (action.type) {
case HYDRATE:
return action.payload;
default: {
const combineReducer = combineReducers({
url,
user,
});
return combineReducer(state, action);
}
}
};
export type RootState = ReturnType<typeof rootReducer>;
export default rootReducer;
reducers / index.ts <-这是您的方法吗?我做了一点修改。
// pages/index.js
import { END } from "redux-saga";
import wrapper from "../store";
export const getServerSideProps = wrapper.getServerSideProps(
async (context) => {
context.store.dispatch({
type: LOAD_USER_REQUEST,
});
context.store.dispatch(END);
await context.store.sagaTask.toPromise();
}
);
我看到了正式文件,但不明白。 [https://github.com/kirill-konshin/next-redux-wrapper#getserversideprops]
这些代码在JavaScript中没有问题。 但是打字稿有问题。
我英语不好。抱歉。
所以想要简单的代码,简单的说明。
谢谢。
答案 0 :(得分:1)
这是我看到的问题:
class GUI(tk.Tk):
"""GUI created from Tkinter"""
def __init__(self,
start_values: Dict[str, Any],
mode: str = 'auto',
verbose: Optional[int] = 3
) -> None:
super().__init__()
self.mode = mode
self.start_values = start_values
self.current_state = self.mode
# GUI window
self.title("Graphic User Interface")
self.verbose = verbose
# Maximizes window when exiting fullscreen mode
# self.state('zoomed') # <-- not supported in Linux
self.attributes("-fullscreen", True)
self.configure(background=background_color)
self.bind("<Escape>", self.end_fullscreen)
self.columnconfigure(0, weight=1)
self.rowconfigure(2, weight=1)
# Title
title = tk.Label(
self,
text="Auto/manual mode",
bg=background_color,
font=("Bodoni bold", 45))
title.grid()
style = ttk.Style()
style.theme_create(
"MyStyle",
parent="alt",
settings={
"TNotebook": {
"configure": {
"tabmargins": [0, 5, 0, 0],
"background": "#ffffff"
}
},
"TNotebook.Tab": {
"configure": {
"padding": [100, 8],
"font": ("MS Serif, bold", 14)
}
}
})
style.theme_use("MyStyle")
# the container is where we'll stack a bunch of frames
# on top of each other, then the one we want visible
# will be raised above the others
container = tk.Frame(self)
container.grid()
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (AutoWindow, ManualWindow):
page_name = F.__name__
frame = F(self.start_values, master=container,
controller=self, background=background_color)
self.frames[page_name] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible.
frame.grid(row=0, column=0, sticky="nsew")
if self.mode == "auto":
self.show_frame("AutoWindow")
elif self.mode == "manual":
self.show_frame("ManualWindow")
else:
raise ValueError("invalid mode format".format(self.mode))
self.toggle_btn = tk.Button(container, text=self.mode, width=12, command=self.toggle)
self.toggle_btn.grid()
def show_frame(self, page_name, state_values=None):
"""Show a frame for the given page name"""
frame = self.frames[page_name]
frame.tkraise()
def end_fullscreen(self, event: Union[str, None] = None) -> str:
"""Toggle full screen"""
self.state = False
self.attributes("-fullscreen", False)
return "break"
def toggle(self):
"""
Get and set the present state of the toggle button
"""
if self.toggle_btn.config('text')[-1] == 'manual':
self.toggle_btn.config(text='auto')
self.current_state = "auto"
return self.current_state
else:
self.toggle_btn.config(text='manual')
self.current_state = "manual"
return self.current_state
class ManualWindow(tk.Frame):
"""The entry window for the GUI
Args:
master: The main GUI
**kwargs: Tkinter's Frame method takes keyword arguments
"""
def __init__(self, start_values, master: Union[Tparent, None] = None,
controller: Union[TMaster, None] = None, **kwargs):
self.frame = tk.Frame.__init__(self, master)
self.controller = controller
self.start_values = start_values.copy()
for key in ['segment', 'step']:
self.start_values.pop(key)
self.current_state = "manual"
self.setpoint = self.start_values
self.bind("<Return>", self.fetch_values)
# Input fields
namelbl = tk.Label(
self,
text=name,
bg=background_color,
font=("Bodoni bold", 30),
pady=25)
namelbl.grid()
input_fields = tk.Frame(self, background=background_color)
input_fields.grid()
for idx, (field, initVal) in enumerate(self.start_values.items()):
Entry(input_fields, field, initVal, idx)
# Buttons
self.set_button = tk.Button(self, text='Set Values', command=self.fetch_values, **button_opts)
self.set_button.grid()
def fetch_values(self,event=None):
"""Fetching input entries"""
data = dict(elem.get() for elem in Entry.instances)
self.setpoint = data
print("values set")
def switch_frame(self, state_values, event=None):
"""update entries before switching"""
ordered = OrderedDict((k, state_values['setpoint'][k])
for k in list(self.start_values.keys()))
# Update the entries
for idx, (field, val) in enumerate(dict(ordered).items()):
if Entry.instances[idx].ent.state == "disabled":
Entry.instances[idx].ent.state = "normal"
Entry.instances[idx].ent.delete('0', 'end')
Entry.instances[idx].ent.insert(tk.END, "{:.2f}".format(float(val)))
super().tkraise()
super().grid()
中遇到错误,因为您的createStore(reducer, enhancer)
不适合类型reducer
。您必须使减速器适合这种类型。现在的问题是您的减速器不允许(state: State | undefined, action: AnyAction) => State
为state
。更改
undefined
到
const rootReducer = (state: State, action: AnyAction) => {
const rootReducer = (state: State | undefined, action: AnyAction): State => {
行会出现错误,因为redux创建的store.sagaTask = sagaMiddleware.run(rootSaga);
对象没有名为store
的属性。关于该here的另一讨论。这是一个基于next-redux-wrapper文档的解决方案:
为商店定义一个包含任务的新界面
sagaTask
替换
export interface SagaStore extends Store<State, AnyAction> {
sagaTask: Task;
}
使用
store.sagaTask = sagaMiddleware.run(rootSaga);
替换
(store as SagaStore).sagaTask = sagaMiddleware.run(rootSaga);
使用
await context.store.sagaTask.toPromise();
答案 1 :(得分:1)
我在尝试以适当的方式将 Redux 与 Next 同步时也遇到了一些麻烦,他们使用 next-redux-wrapper 创建了一个项目模板,该模板目前正在工作并遵循 next- redux 包装器。你可以看看:
https://github.com/felipemeriga/next-typescript-redux-template
基本上我是这样创建包装的:
const thunkMiddleware = thunk.withExtraArgument({}) as ThunkMiddleware<IStoreState, AnyAction>;
// create a makeStore function
// This makeStore is needed for the wrapper, for every new page that is called, a new store with the current values will be created
const makeStore: MakeStore<IStoreState> = (context: Context) => createStore(reducers, composeWithDevTools(applyMiddleware(thunkMiddleware)));
export type ExtraArgument = {};
export type ThunkCreator<R = Promise<any>> = ActionCreator<ThunkAction<R, IStoreState, ExtraArgument, AnyAction>>;
// export an assembled wrapper
// this wrapper will be used to every page's component, for injecting the store and actions into it.
const wrapper = createWrapper<IStoreState>(makeStore, {debug: false});
export default wrapper;
然后覆盖_app.tsx:
// For default you don't need to edit _app.tsx, but if you want to wrapper the pages with redux wrapper, you need
// to override _app.tsx with this code bellow
class MyApp extends App {
// @ts-ignore
static async getInitialProps({Component, ctx}) {
return {
pageProps: {
// Call page-level getInitialProps
...(Component.getInitialProps ? await Component.getInitialProps(ctx) : {}),
}
};
}
render() {
const {Component, pageProps} = this.props;
return (
<Component {...pageProps} />
);
}
}
export default wrapper.withRedux(MyApp);
最后注入 index.tsx 组件:
interface IProps {
tick: ITickState
updateAnnouncement: any
}
interface IState {}
interface IDispatchProps {
onUpdateTick: (message: string) => ITickState,
thunkAsyncFunction: () => Promise<any>;
}
type Props = IProps & IState & IDispatchProps
class App extends React.Component<Props> {
constructor(props: Props) {
super(props);
}
async componentWillUnmount(): Promise<void> {
await this.props.thunkAsyncFunction();
}
render() {
return (
<Layout title="Home | Next.js + TypeScript Example">
<h1>Hello Next.js ?</h1>
<p>
<Link href="/about">
<a>About</a>
</Link>
</p>
<div>
The current tick state: {this.props.tick.message}
</div>
</Layout>
);
}
}
const mapStateToProps = (state: IStoreState): {tick: ITickState} => ({
tick: getTickState(state)
});
const mapDispatchToProps = (dispatch: any): IDispatchProps => {
return {
onUpdateTick: (message: string) =>
dispatch(updateTick(message)),
thunkAsyncFunction: () => dispatch(thunkAsyncFunction())
}
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
// As the wrapper is injected in _app.tsx, for every component(page) that will interact with Redux and Thunk
// you need to place this piece of code bellow, that will get the static props from the wrapper, and inject on your
// component
export const getStaticProps = wrapper.getStaticProps(
({}) => {
}
);