82191


紆余曲折あり、コードが以下のようになりました。  
AWSのS3とも接続でき、コンソールにオブジェクトの名前を表示するところまで出来ました。  
最終的にはJSXでブラウザに表示させたいです。({list2}の部分)  
なぜか何も出てこなく、途方に暮れております。

何が間違っているのか、ご教示ください。  
宜しくお願い致します。

[code]

    import Amplify, { Storage } from 'aws-amplify';
    import { AmplifyAuthenticator, AmplifySignUp, AmplifySignOut } from '@aws-amplify/ui-react';
    import { AuthState, onAuthUIStateChange } from '@aws-amplify/ui-components';
    import awsconfig from './aws-exports';
    import AWS from 'aws-sdk';
    import { Bucket } from '@aws-sdk/client-s3';
    
    Amplify.configure(awsconfig);
    
    const App = () => {
        const [name, setName] = useState('')
        const [file, setFile] = useState('')
        const [response, setResponse] = useState('')
    
        const [authState, setAuthState] = React.useState();
        const [user, setUser] = React.useState();
    
        React.useEffect(() => {
            return onAuthUIStateChange((nextAuthState, authData) => {
                setAuthState(nextAuthState);
                setUser(authData)
            });
        }, []);
    
        const onChange = (e) => {
        e.preventDefault()
        if (e.target.files[0] !== null) {
          setFile(e.target.files[0])
          setName(e.target.files[0].name)
        }
      }
      const onSubmit = (e) => {
        e.preventDefault()
        if (file) {
          Storage.put(name, file, {
            /* level: 'protected', */
            contentType: file.type,
          })
            .then((result) => {
              console.log(result)
              setResponse(`Success uploading file: ${name}!`)
            })
            .then(() => {
              document.getElementById('file-input').value = null
              setFile(null)
            })
            .catch((err) => {
              console.log(err)
              setResponse(`Can't upload file: ${err}`)
            })
        } else {
          setResponse(`Files needed!`)
        }
      }
      
      // Set the region 
    AWS.config.update({
      region: 'ap-northeast-1',
      accessKeyId: 'アクセスキー',
      secretAccessKey: 'シークレットキー'})
    
    // Create S3 service object
    var s3 = new AWS.S3({apiVersion: '2006-03-01'})
    
    // Create the parameters for calling listObjects
    var bucketParams = {
    Bucket : '任意のバケット名',
    };
    var list1 = []
    var list2 = []
    // Call S3 to obtain a list of the objects in the bucket
    s3.listObjects(bucketParams, function(err, data) {
    if (err) {
      console.log("Error", err);
    } else {
      for (let i= 0;i < data.Contents.length; i++) {
        list1.push(data.Contents[i]);
        console.log(data.Contents[i].Key); //これもコンソールに出力される
      }
      for(var d in list1){
        console.log(list1[d].Key);　//これもコンソールに出力される
        list2.push('{Key:\'' + list1[d].Key + '\'}');
        console.log(list2[0])
      } 
    }
    })
        return authState === AuthState.SignedIn && user ? (
          <div className="App">
              <div>Hello, {user.username}</div>
              <div className='video-uploader'>
                <form onSubmit={(e) => onSubmit(e)}>
                <p>
                  <label className='select-label'>Select video: </label>
                </p>
                <p>
                  <input
                    className='video-input'
                    type='file'
                    id='file-input'
                    accept='image/*, video/*'
                    onChange={(e) => onChange(e)}
                  />
                </p>
                <button type='submit' className='btn'>Submit</button>
              </form>
              <div>{list2.map((value) => <p>{value.Key}</p>)}
              </div>
              
              </div>
                
              <AmplifySignOut />
          </div>
        ) : (
          <AmplifyAuthenticator>
            <AmplifySignUp
              slot="sign-up"
              formFields={[
                { type: "username" },
                { type: "password" },
                { type: "email" }
              ]}
            />
          </AmplifyAuthenticator>
      );
    }
    
    export default App;
    
[/code]


CC BY-SA 4.0
2021-09-01T07:14:10.660
81157
2021-09-02T22:08:33.383
2021-09-01T11:24:52.193
19110
39728
question
reactjs
{list2.map((value) => <p>{value.Key}</p>)の部分が表示されない理由を知りたい


レンダリング時点では常に `list2` が空配列だからです。`listObjects`
の第2引数コールバックが実行される前にレンダリングが行われていると推測します。

* * *
[code]

    console.log('A');
    s3.listObjects(bucketParams, function(err, data) {
      console.log('B');
    });
    console.log('C');
    
[/code]

このコードの出力順は A -> C -> B になるのではないでしょうか？

もしこの挙動に疑問があれば、まず非同期処理とコールバックについて学習すると良いと思います。例えば次の資料は丁寧に説明しています。

参考: <https://jsprimer.net/basic/async/>

* * *

では React ではどうするのか？

<https://ja.reactjs.org/docs/faq-ajax.html>  
この章 "AJAX と API" はまさに、非同期処理の結果をレンダリングする方法を説明しています。

最小限のイメージとしては次のようになるでしょう。

[code]

    const App = () => {
      const [s3Objects, setS3Objects] = useState([]);
    
      useEffect(() => {
        const s3 = new AWS.S3({apiVersion: '2006-03-01'});
        s3.listObjects(bucketParams, function(err, data) {
          if (err) {
            console.log("Error", err);
          } else {
            setS3Objects(data.Contents); // setS3Objectsを呼ぶことで再度レンダリングが行われる。
          }
      }, []);
    
      return (
        <div>
          {s3Objects.map((o) => <p>{o.Key}</p>)}
        </div>
      );
    };
    
[/code]

この App コンポーネントは2回レンダリングが行われます。1回目は `s3Objects` は空配列。2回目は実際のオブジェクト名のリストが入っています。


CC BY-SA 4.0
2021-09-02T22:08:33.383
82191
2021-09-02T22:08:33.383
32959
81157
answer