質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Redux

Reduxは、JavaScriptアプリケーションの状態を管理するためのオープンソースライブラリです。ReactやAngularで一般的にユーザーインターフェイスの構築に利用されます。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

1回答

859閲覧

ReactとReduxの使い方が分からず

v_v

総合スコア47

Redux

Reduxは、JavaScriptアプリケーションの状態を管理するためのオープンソースライブラリです。ReactやAngularで一般的にユーザーインターフェイスの構築に利用されます。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2022/06/26 10:20

やっていること

RustのGUIフレームワーク、Tauriを使用してGUIを書いています。
ReactとReduxを使い、GUI(タブ分割)を実現したいと思っています。

やりたいこと

ボタンをクリックしたらRust側でカウントを1増やす。
UI側でタブを別タブに切り替える
戻したときにUIのステートが切り替える前と同じ状態に戻っていること

コード

rust

1#![cfg_attr( 2 all(not(debug_assertions), target_os = "windows"), 3 windows_subsystem = "windows" 4)] 5 6fn main() { 7 let context = tauri::generate_context!(); 8 tauri::Builder::default() 9 .invoke_handler(tauri::generate_handler![countup,]) 10 .menu(tauri::Menu::os_default(&context.package_info().name)) 11 .run(context) 12 .expect("error while running tauri application"); 13} 14 15#[tauri::command] 16fn countup(count: i32) -> i32 { 17 println!("{}", count + 1); 18 count + 1 19}

UI側

package.json

1{ 2 "name": "tauri-app", 3 "version": "0.1.0", 4 "private": true, 5 "dependencies": { 6 "@reduxjs/toolkit": "^1.8.2", 7 "@tauri-apps/api": "^1.0.1", 8 "@testing-library/jest-dom": "^5.16.4", 9 "@testing-library/react": "^13.3.0", 10 "@testing-library/user-event": "^13.5.0", 11 "@types/jest": "^27.5.2", 12 "@types/node": "^16.11.41", 13 "@types/react": "^18.0.14", 14 "@types/react-dom": "^18.0.5", 15 "@types/react-redux": "^7.1.24", 16 "react": "^18.2.0", 17 "react-dom": "^18.2.0", 18 "react-redux": "file:types/react-redux@reduxjs/toolkit", 19 "react-scripts": "^5.0.1", 20 "react-tabs": "^5.1.0", 21 "typescript": "^4.7.4", 22 "web-vitals": "^2.1.4" 23 }, 24 "scripts": { 25 "start": "cross-env BROWSER=none react-scripts start", 26 "build": "react-scripts build", 27 "test": "react-scripts test", 28 "eject": "react-scripts eject", 29 "tauri": "tauri" 30 }, 31 "eslintConfig": { 32 "extends": [ 33 "react-app", 34 "react-app/jest" 35 ] 36 }, 37 "browserslist": { 38 "production": [ 39 ">0.2%", 40 "not dead", 41 "not op_mini all" 42 ], 43 "development": [ 44 "last 1 chrome version", 45 "last 1 firefox version", 46 "last 1 safari version" 47 ] 48 }, 49 "devDependencies": { 50 "@tauri-apps/cli": "^1.0.0", 51 "cross-env": "^7.0.3" 52 } 53}

App.tsx

1import React from 'react'; 2import './App.css'; 3import './tab_style.css' 4// import 'react-tabs/style/react-tabs.css'; 5import { invoke } from '@tauri-apps/api'; 6import { Tab, Tabs, TabList, TabPanel } from 'react-tabs'; 7import { TabPage1 } from './TabPages/TabPage1' 8 9class App extends React.Component { 10 render(): React.ReactNode { 11 return ( 12 <div className="App"> 13 <TabUI></TabUI> 14 </div> 15 ); 16 } 17} 18 19class TabUI extends React.Component { 20 state = { 21 value: 0, 22 }; 23 24 handleChange = (value: any) => { 25 this.setState({ value }); 26 console.log(value) 27 }; 28 render() { 29 const { value } = this.state; 30 return (<div id="react_tab_conainer"> 31 <Tabs 32 value={value} onChange={this.handleChange}> 33 <TabList> 34 <Tab>Counter</Tab> 35 <Tab>Bar</Tab> 36 <Tab>Baz</Tab> 37 </TabList> 38 <TabPanel> 39 <TabPage1></TabPage1> 40 </TabPanel> 41 <TabPanel> 42 {Page2()} 43 </TabPanel> 44 <TabPanel> 45 Baz 46 </TabPanel> 47 </Tabs> 48 </div > 49 ) 50 } 51} 52 53 54function Page2() { 55 return (<div className="panel-content"></div>) 56} 57 58export default App;

store.tsx

1import { configureStore, createSlice } from '@reduxjs/toolkit' 2import { TabPage1, TabPage1Slice } from './TabPages/TabPage1' 3 4const store = configureStore({ 5 reducer: TabPage1Slice.reducer 6});
import React from 'react'; import './../App.css'; import './../tab_style.css' // import 'react-tabs/style/react-tabs.css'; import { invoke } from '@tauri-apps/api'; import { configureStore, createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit' import { useSelector, useDispatch } from 'react-redux'; // 非同期 const clickAsync = createAsyncThunk( "rust/count", async (count: number) => { return await invoke("countup", { count: count }); } ); export const TabPage1Slice = createSlice({ name: 'TabPage1Slice', initialState: { counter: 0 }, reducers: {}, extraReducers: (builder) => { builder.addCase(clickAsync.fulfilled, (state, action: PayloadAction<any>) => { state.counter = action.payload; }); } }); export class TabPage1 extends React.Component<{}, { counter: number }>{ constructor(props: any) { super(props) this.state = { counter: 0 } } render(): React.ReactNode { const dispatch = useDispatch(); return (<Counter handleClick={() => { dispatch(clickAsync(this.state.counter)) }} counter={this.state.counter} > </Counter>) } } function Counter(props: any) { return ( <div className="panel-content" > <button onClick={props.handleClick}> Click</button> <label> {props.counter} </label> </div> ) }

発生しているエラー

ERROR [eslint] src\TabPages\TabPage1.tsx Line 40:26: React Hook "useDispatch" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks Search for the keywords to learn more about each error. ERROR [eslint] src\TabPages\TabPage1.tsx Line 40:26: React Hook "useDispatch" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks Search for the keywords to learn more about each error. ERROR in src/TabPages/TabPage1.tsx:41:56 TS2345: Argument of type 'AsyncThunkAction<RejectWithValue<unknown, unknown>, number, {}>' is not assignable to parameter of type 'AnyAction'. 39 | render(): React.ReactNode { 40 | const dispatch = useDispatch(); > 41 | return (<Counter handleClick={() => { dispatch(clickAsync(this.state.counter)) }} counter={this.state.counter} > </Counter>) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 42 | } 43 | } 44 |

TypeScriptとReactが分からなさすぎてエラーを読んでも理解が出来ません。
具体的に何をどうしたらいいのでしょうか?

すごくふわっとしていて申し訳ないんですが、宜しくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2022/06/26 10:36

とりあえずエラーは TabPage1 がクラスコンポーネントなので useDispatch などの hook 関数は使えません。 React の使い方というか、そもそも React とは何かについては、ちゃんと体系立てて学ぶことをお勧めします。サンプルコードを適当にいじれば何となく分かる、といった代物ではないので。
guest

回答1

0

自己解決

Tauri側のステート管理機能を使うとRedux使わずにステート管理ができました。
サクッと実装するレベルならこちらで十分でした。

rust

1#![cfg_attr( 2 all(not(debug_assertions), target_os = "windows"), 3 windows_subsystem = "windows" 4)] 5 6fn main() { 7 let context = tauri::generate_context!(); 8 tauri::Builder::default() 9 .manage(Tab1State { 10 counter: Mutex::new(0), 11 }) 12 .invoke_handler(tauri::generate_handler![countup, get_counter]) 13 .menu(tauri::Menu::os_default(&context.package_info().name)) 14 .run(context) 15 .expect("error while running tauri application"); 16} 17use std::sync::{Arc, Mutex}; 18use tauri::State; 19#[derive(Debug)] 20pub struct Tab1State { 21 pub counter: Mutex<i32>, 22} 23#[tauri::command] 24fn countup(counter: State<Tab1State>) -> i32 { 25 let mut counter = counter.counter.lock().unwrap(); 26 *counter += 1; 27 println!("{}", counter); 28 *counter 29} 30 31#[tauri::command] 32fn reset(counter: State<Tab1State>) -> i32 { 33 let mut counter = counter.counter.lock().unwrap(); 34 *counter = 0; 35 0 36} 37#[tauri::command] 38fn get_counter(counter: State<Tab1State>) -> i32 { 39 let mut counter = counter.counter.lock().unwrap(); 40 *counter 41}

TabPage1.tsx

1import React from 'react'; 2import './../App.css'; 3import './../tab_style.css' 4// import 'react-tabs/style/react-tabs.css'; 5import { invoke } from '@tauri-apps/api'; 6 7export class TabPage1 extends React.Component<{}, { counter: number }>{ 8 constructor(props: any) { 9 super(props) 10 this.state = { 11 counter: 0 12 } 13 } 14 componentDidMount() { 15 console.log("tab1 mount"); 16 this.get_count().then((ret) => this.setState({ counter: ret as number })) 17 } 18 componentWillUnmount() { 19 // タブ切り替えが起こるときに走る。 20 // ステートの保存をする。 21 console.log("tab1 unmount") 22 } 23 get_count() { 24 return invoke("get_counter") 25 } 26 click() { 27 invoke("countup").then((ret) => this.setState({ counter: ret as number })); 28 } 29 render(): React.ReactNode { 30 return (<Counter handleClick={() => { this.click() }} counter={this.state.counter} > </Counter>) 31 32 } 33} 34 35function Counter(props: any) { 36 return ( 37 <div className="panel-content" > <button onClick={props.handleClick}> Click</button> 38 <label> {props.counter} </label> 39 </div> 40 ) 41}

App.tsx

1import React from 'react'; 2import './App.css'; 3import './tab_style.css' 4// import 'react-tabs/style/react-tabs.css'; 5import { Tab, Tabs, TabList, TabPanel } from 'react-tabs'; 6import { TabPage1 } from './TabPages/TabPage1' 7 8class App extends React.Component { 9 render(): React.ReactNode { 10 return ( 11 <div className="App"> 12 <TabUI></TabUI> 13 </div> 14 ); 15 } 16} 17 18class TabUI extends React.Component { 19 state = { 20 value: 0, 21 }; 22 23 handleChange = (value: any) => { 24 this.setState({ value }); 25 console.log(value) 26 }; 27 render() { 28 const { value } = this.state; 29 return (<div id="react_tab_conainer"> 30 <Tabs 31 value={value} onChange={this.handleChange}> 32 <TabList> 33 <Tab>Counter</Tab> 34 <Tab>Bar</Tab> 35 <Tab>Baz</Tab> 36 </TabList> 37 <TabPanel> 38 <TabPage1></TabPage1> 39 </TabPanel> 40 <TabPanel> 41 {Page2()} 42 </TabPanel> 43 <TabPanel> 44 Baz 45 </TabPanel> 46 </Tabs> 47 </div > 48 ) 49 } 50} 51 52 53function Page2() { 54 return (<div className="panel-content"></div>) 55} 56 57export default App;

投稿2022/06/27 00:54

v_v

総合スコア47

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問